Passed
Push — master ( f0dd71...c56a27 )
by Christoph
11:49 queued 12s
created
lib/private/AppFramework/App.php 2 patches
Indentation   +157 added lines, -157 removed lines patch added patch discarded remove patch
@@ -47,167 +47,167 @@
 block discarded – undo
47 47
  */
48 48
 class App {
49 49
 
50
-	/** @var string[] */
51
-	private static $nameSpaceCache = [];
52
-
53
-	/**
54
-	 * Turns an app id into a namespace by either reading the appinfo.xml's
55
-	 * namespace tag or uppercasing the appid's first letter
56
-	 * @param string $appId the app id
57
-	 * @param string $topNamespace the namespace which should be prepended to
58
-	 * the transformed app id, defaults to OCA\
59
-	 * @return string the starting namespace for the app
60
-	 */
61
-	public static function buildAppNamespace(string $appId, string $topNamespace='OCA\\'): string {
62
-		// Hit the cache!
63
-		if (isset(self::$nameSpaceCache[$appId])) {
64
-			return $topNamespace . self::$nameSpaceCache[$appId];
65
-		}
66
-
67
-		$appInfo = \OC_App::getAppInfo($appId);
68
-		if (isset($appInfo['namespace'])) {
69
-			self::$nameSpaceCache[$appId] = trim($appInfo['namespace']);
70
-		} else {
71
-			if ($appId !== 'spreed') {
72
-				// if the tag is not found, fall back to uppercasing the first letter
73
-				self::$nameSpaceCache[$appId] = ucfirst($appId);
74
-			} else {
75
-				// For the Talk app (appid spreed) the above fallback doesn't work.
76
-				// This leads to a problem when trying to install it freshly,
77
-				// because the apps namespace is already registered before the
78
-				// app is downloaded from the appstore, because of the hackish
79
-				// global route index.php/call/{token} which is registered via
80
-				// the core/routes.php so it does not have the app namespace.
81
-				// @ref https://github.com/nextcloud/server/pull/19433
82
-				self::$nameSpaceCache[$appId] = 'Talk';
83
-			}
84
-		}
85
-
86
-		return $topNamespace . self::$nameSpaceCache[$appId];
87
-	}
88
-
89
-
90
-	/**
91
-	 * Shortcut for calling a controller method and printing the result
92
-	 * @param string $controllerName the name of the controller under which it is
93
-	 *                               stored in the DI container
94
-	 * @param string $methodName the method that you want to call
95
-	 * @param DIContainer $container an instance of a pimple container.
96
-	 * @param array $urlParams list of URL parameters (optional)
97
-	 * @throws HintException
98
-	 */
99
-	public static function main(string $controllerName, string $methodName, DIContainer $container, array $urlParams = null) {
100
-		if (!is_null($urlParams)) {
101
-			$container->query(IRequest::class)->setUrlParameters($urlParams);
102
-		} else if (isset($container['urlParams']) && !is_null($container['urlParams'])) {
103
-			$container->query(IRequest::class)->setUrlParameters($container['urlParams']);
104
-		}
105
-		$appName = $container['AppName'];
106
-
107
-		// first try $controllerName then go for \OCA\AppName\Controller\$controllerName
108
-		try {
109
-			$controller = $container->query($controllerName);
110
-		} catch(QueryException $e) {
111
-			if (strpos($controllerName, '\\Controller\\') !== false) {
112
-				// This is from a global registered app route that is not enabled.
113
-				[/*OC(A)*/, $app, /* Controller/Name*/] = explode('\\', $controllerName, 3);
114
-				throw new HintException('App ' . strtolower($app) . ' is not enabled');
115
-			}
116
-
117
-			if ($appName === 'core') {
118
-				$appNameSpace = 'OC\\Core';
119
-			} else {
120
-				$appNameSpace = self::buildAppNamespace($appName);
121
-			}
122
-			$controllerName = $appNameSpace . '\\Controller\\' . $controllerName;
123
-			$controller = $container->query($controllerName);
124
-		}
125
-
126
-		// initialize the dispatcher and run all the middleware before the controller
127
-		/** @var Dispatcher $dispatcher */
128
-		$dispatcher = $container['Dispatcher'];
129
-
130
-		list(
131
-			$httpHeaders,
132
-			$responseHeaders,
133
-			$responseCookies,
134
-			$output,
135
-			$response
136
-		) = $dispatcher->dispatch($controller, $methodName);
137
-
138
-		$io = $container[IOutput::class];
139
-
140
-		if(!is_null($httpHeaders)) {
141
-			$io->setHeader($httpHeaders);
142
-		}
143
-
144
-		foreach($responseHeaders as $name => $value) {
145
-			$io->setHeader($name . ': ' . $value);
146
-		}
147
-
148
-		foreach($responseCookies as $name => $value) {
149
-			$expireDate = null;
150
-			if($value['expireDate'] instanceof \DateTime) {
151
-				$expireDate = $value['expireDate']->getTimestamp();
152
-			}
153
-			$io->setCookie(
154
-				$name,
155
-				$value['value'],
156
-				$expireDate,
157
-				$container->getServer()->getWebRoot(),
158
-				null,
159
-				$container->getServer()->getRequest()->getServerProtocol() === 'https',
160
-				true
161
-			);
162
-		}
163
-
164
-		/*
50
+    /** @var string[] */
51
+    private static $nameSpaceCache = [];
52
+
53
+    /**
54
+     * Turns an app id into a namespace by either reading the appinfo.xml's
55
+     * namespace tag or uppercasing the appid's first letter
56
+     * @param string $appId the app id
57
+     * @param string $topNamespace the namespace which should be prepended to
58
+     * the transformed app id, defaults to OCA\
59
+     * @return string the starting namespace for the app
60
+     */
61
+    public static function buildAppNamespace(string $appId, string $topNamespace='OCA\\'): string {
62
+        // Hit the cache!
63
+        if (isset(self::$nameSpaceCache[$appId])) {
64
+            return $topNamespace . self::$nameSpaceCache[$appId];
65
+        }
66
+
67
+        $appInfo = \OC_App::getAppInfo($appId);
68
+        if (isset($appInfo['namespace'])) {
69
+            self::$nameSpaceCache[$appId] = trim($appInfo['namespace']);
70
+        } else {
71
+            if ($appId !== 'spreed') {
72
+                // if the tag is not found, fall back to uppercasing the first letter
73
+                self::$nameSpaceCache[$appId] = ucfirst($appId);
74
+            } else {
75
+                // For the Talk app (appid spreed) the above fallback doesn't work.
76
+                // This leads to a problem when trying to install it freshly,
77
+                // because the apps namespace is already registered before the
78
+                // app is downloaded from the appstore, because of the hackish
79
+                // global route index.php/call/{token} which is registered via
80
+                // the core/routes.php so it does not have the app namespace.
81
+                // @ref https://github.com/nextcloud/server/pull/19433
82
+                self::$nameSpaceCache[$appId] = 'Talk';
83
+            }
84
+        }
85
+
86
+        return $topNamespace . self::$nameSpaceCache[$appId];
87
+    }
88
+
89
+
90
+    /**
91
+     * Shortcut for calling a controller method and printing the result
92
+     * @param string $controllerName the name of the controller under which it is
93
+     *                               stored in the DI container
94
+     * @param string $methodName the method that you want to call
95
+     * @param DIContainer $container an instance of a pimple container.
96
+     * @param array $urlParams list of URL parameters (optional)
97
+     * @throws HintException
98
+     */
99
+    public static function main(string $controllerName, string $methodName, DIContainer $container, array $urlParams = null) {
100
+        if (!is_null($urlParams)) {
101
+            $container->query(IRequest::class)->setUrlParameters($urlParams);
102
+        } else if (isset($container['urlParams']) && !is_null($container['urlParams'])) {
103
+            $container->query(IRequest::class)->setUrlParameters($container['urlParams']);
104
+        }
105
+        $appName = $container['AppName'];
106
+
107
+        // first try $controllerName then go for \OCA\AppName\Controller\$controllerName
108
+        try {
109
+            $controller = $container->query($controllerName);
110
+        } catch(QueryException $e) {
111
+            if (strpos($controllerName, '\\Controller\\') !== false) {
112
+                // This is from a global registered app route that is not enabled.
113
+                [/*OC(A)*/, $app, /* Controller/Name*/] = explode('\\', $controllerName, 3);
114
+                throw new HintException('App ' . strtolower($app) . ' is not enabled');
115
+            }
116
+
117
+            if ($appName === 'core') {
118
+                $appNameSpace = 'OC\\Core';
119
+            } else {
120
+                $appNameSpace = self::buildAppNamespace($appName);
121
+            }
122
+            $controllerName = $appNameSpace . '\\Controller\\' . $controllerName;
123
+            $controller = $container->query($controllerName);
124
+        }
125
+
126
+        // initialize the dispatcher and run all the middleware before the controller
127
+        /** @var Dispatcher $dispatcher */
128
+        $dispatcher = $container['Dispatcher'];
129
+
130
+        list(
131
+            $httpHeaders,
132
+            $responseHeaders,
133
+            $responseCookies,
134
+            $output,
135
+            $response
136
+        ) = $dispatcher->dispatch($controller, $methodName);
137
+
138
+        $io = $container[IOutput::class];
139
+
140
+        if(!is_null($httpHeaders)) {
141
+            $io->setHeader($httpHeaders);
142
+        }
143
+
144
+        foreach($responseHeaders as $name => $value) {
145
+            $io->setHeader($name . ': ' . $value);
146
+        }
147
+
148
+        foreach($responseCookies as $name => $value) {
149
+            $expireDate = null;
150
+            if($value['expireDate'] instanceof \DateTime) {
151
+                $expireDate = $value['expireDate']->getTimestamp();
152
+            }
153
+            $io->setCookie(
154
+                $name,
155
+                $value['value'],
156
+                $expireDate,
157
+                $container->getServer()->getWebRoot(),
158
+                null,
159
+                $container->getServer()->getRequest()->getServerProtocol() === 'https',
160
+                true
161
+            );
162
+        }
163
+
164
+        /*
165 165
 		 * Status 204 does not have a body and no Content Length
166 166
 		 * Status 304 does not have a body and does not need a Content Length
167 167
 		 * https://tools.ietf.org/html/rfc7230#section-3.3
168 168
 		 * https://tools.ietf.org/html/rfc7230#section-3.3.2
169 169
 		 */
170
-		$emptyResponse = false;
171
-		if (preg_match('/^HTTP\/\d\.\d (\d{3}) .*$/', $httpHeaders, $matches)) {
172
-			$status = (int)$matches[1];
173
-			if ($status === Http::STATUS_NO_CONTENT || $status === Http::STATUS_NOT_MODIFIED) {
174
-				$emptyResponse = true;
175
-			}
176
-		}
177
-
178
-		if (!$emptyResponse) {
179
-			if ($response instanceof ICallbackResponse) {
180
-				$response->callback($io);
181
-			} else if (!is_null($output)) {
182
-				$io->setHeader('Content-Length: ' . strlen($output));
183
-				$io->setOutput($output);
184
-			}
185
-		}
186
-
187
-	}
188
-
189
-	/**
190
-	 * Shortcut for calling a controller method and printing the result.
191
-	 * Similar to App:main except that no headers will be sent.
192
-	 * This should be used for example when registering sections via
193
-	 * \OC\AppFramework\Core\API::registerAdmin()
194
-	 *
195
-	 * @param string $controllerName the name of the controller under which it is
196
-	 *                               stored in the DI container
197
-	 * @param string $methodName the method that you want to call
198
-	 * @param array $urlParams an array with variables extracted from the routes
199
-	 * @param DIContainer $container an instance of a pimple container.
200
-	 */
201
-	public static function part(string $controllerName, string $methodName, array $urlParams,
202
-								DIContainer $container) {
203
-
204
-		$container['urlParams'] = $urlParams;
205
-		$controller = $container[$controllerName];
206
-
207
-		$dispatcher = $container['Dispatcher'];
208
-
209
-		list(, , $output) =  $dispatcher->dispatch($controller, $methodName);
210
-		return $output;
211
-	}
170
+        $emptyResponse = false;
171
+        if (preg_match('/^HTTP\/\d\.\d (\d{3}) .*$/', $httpHeaders, $matches)) {
172
+            $status = (int)$matches[1];
173
+            if ($status === Http::STATUS_NO_CONTENT || $status === Http::STATUS_NOT_MODIFIED) {
174
+                $emptyResponse = true;
175
+            }
176
+        }
177
+
178
+        if (!$emptyResponse) {
179
+            if ($response instanceof ICallbackResponse) {
180
+                $response->callback($io);
181
+            } else if (!is_null($output)) {
182
+                $io->setHeader('Content-Length: ' . strlen($output));
183
+                $io->setOutput($output);
184
+            }
185
+        }
186
+
187
+    }
188
+
189
+    /**
190
+     * Shortcut for calling a controller method and printing the result.
191
+     * Similar to App:main except that no headers will be sent.
192
+     * This should be used for example when registering sections via
193
+     * \OC\AppFramework\Core\API::registerAdmin()
194
+     *
195
+     * @param string $controllerName the name of the controller under which it is
196
+     *                               stored in the DI container
197
+     * @param string $methodName the method that you want to call
198
+     * @param array $urlParams an array with variables extracted from the routes
199
+     * @param DIContainer $container an instance of a pimple container.
200
+     */
201
+    public static function part(string $controllerName, string $methodName, array $urlParams,
202
+                                DIContainer $container) {
203
+
204
+        $container['urlParams'] = $urlParams;
205
+        $controller = $container[$controllerName];
206
+
207
+        $dispatcher = $container['Dispatcher'];
208
+
209
+        list(, , $output) =  $dispatcher->dispatch($controller, $methodName);
210
+        return $output;
211
+    }
212 212
 
213 213
 }
Please login to merge, or discard this patch.
Spacing   +14 added lines, -14 removed lines patch added patch discarded remove patch
@@ -58,10 +58,10 @@  discard block
 block discarded – undo
58 58
 	 * the transformed app id, defaults to OCA\
59 59
 	 * @return string the starting namespace for the app
60 60
 	 */
61
-	public static function buildAppNamespace(string $appId, string $topNamespace='OCA\\'): string {
61
+	public static function buildAppNamespace(string $appId, string $topNamespace = 'OCA\\'): string {
62 62
 		// Hit the cache!
63 63
 		if (isset(self::$nameSpaceCache[$appId])) {
64
-			return $topNamespace . self::$nameSpaceCache[$appId];
64
+			return $topNamespace.self::$nameSpaceCache[$appId];
65 65
 		}
66 66
 
67 67
 		$appInfo = \OC_App::getAppInfo($appId);
@@ -83,7 +83,7 @@  discard block
 block discarded – undo
83 83
 			}
84 84
 		}
85 85
 
86
-		return $topNamespace . self::$nameSpaceCache[$appId];
86
+		return $topNamespace.self::$nameSpaceCache[$appId];
87 87
 	}
88 88
 
89 89
 
@@ -107,11 +107,11 @@  discard block
 block discarded – undo
107 107
 		// first try $controllerName then go for \OCA\AppName\Controller\$controllerName
108 108
 		try {
109 109
 			$controller = $container->query($controllerName);
110
-		} catch(QueryException $e) {
110
+		} catch (QueryException $e) {
111 111
 			if (strpos($controllerName, '\\Controller\\') !== false) {
112 112
 				// This is from a global registered app route that is not enabled.
113 113
 				[/*OC(A)*/, $app, /* Controller/Name*/] = explode('\\', $controllerName, 3);
114
-				throw new HintException('App ' . strtolower($app) . ' is not enabled');
114
+				throw new HintException('App '.strtolower($app).' is not enabled');
115 115
 			}
116 116
 
117 117
 			if ($appName === 'core') {
@@ -119,7 +119,7 @@  discard block
 block discarded – undo
119 119
 			} else {
120 120
 				$appNameSpace = self::buildAppNamespace($appName);
121 121
 			}
122
-			$controllerName = $appNameSpace . '\\Controller\\' . $controllerName;
122
+			$controllerName = $appNameSpace.'\\Controller\\'.$controllerName;
123 123
 			$controller = $container->query($controllerName);
124 124
 		}
125 125
 
@@ -137,17 +137,17 @@  discard block
 block discarded – undo
137 137
 
138 138
 		$io = $container[IOutput::class];
139 139
 
140
-		if(!is_null($httpHeaders)) {
140
+		if (!is_null($httpHeaders)) {
141 141
 			$io->setHeader($httpHeaders);
142 142
 		}
143 143
 
144
-		foreach($responseHeaders as $name => $value) {
145
-			$io->setHeader($name . ': ' . $value);
144
+		foreach ($responseHeaders as $name => $value) {
145
+			$io->setHeader($name.': '.$value);
146 146
 		}
147 147
 
148
-		foreach($responseCookies as $name => $value) {
148
+		foreach ($responseCookies as $name => $value) {
149 149
 			$expireDate = null;
150
-			if($value['expireDate'] instanceof \DateTime) {
150
+			if ($value['expireDate'] instanceof \DateTime) {
151 151
 				$expireDate = $value['expireDate']->getTimestamp();
152 152
 			}
153 153
 			$io->setCookie(
@@ -169,7 +169,7 @@  discard block
 block discarded – undo
169 169
 		 */
170 170
 		$emptyResponse = false;
171 171
 		if (preg_match('/^HTTP\/\d\.\d (\d{3}) .*$/', $httpHeaders, $matches)) {
172
-			$status = (int)$matches[1];
172
+			$status = (int) $matches[1];
173 173
 			if ($status === Http::STATUS_NO_CONTENT || $status === Http::STATUS_NOT_MODIFIED) {
174 174
 				$emptyResponse = true;
175 175
 			}
@@ -179,7 +179,7 @@  discard block
 block discarded – undo
179 179
 			if ($response instanceof ICallbackResponse) {
180 180
 				$response->callback($io);
181 181
 			} else if (!is_null($output)) {
182
-				$io->setHeader('Content-Length: ' . strlen($output));
182
+				$io->setHeader('Content-Length: '.strlen($output));
183 183
 				$io->setOutput($output);
184 184
 			}
185 185
 		}
@@ -206,7 +206,7 @@  discard block
 block discarded – undo
206 206
 
207 207
 		$dispatcher = $container['Dispatcher'];
208 208
 
209
-		list(, , $output) =  $dispatcher->dispatch($controller, $methodName);
209
+		list(,, $output) = $dispatcher->dispatch($controller, $methodName);
210 210
 		return $output;
211 211
 	}
212 212
 
Please login to merge, or discard this patch.
lib/private/DB/Connection.php 2 patches
Indentation   +406 added lines, -406 removed lines patch added patch discarded remove patch
@@ -47,410 +47,410 @@
 block discarded – undo
47 47
 use OCP\PreConditionNotMetException;
48 48
 
49 49
 class Connection extends ReconnectWrapper implements IDBConnection {
50
-	/**
51
-	 * @var string $tablePrefix
52
-	 */
53
-	protected $tablePrefix;
54
-
55
-	/**
56
-	 * @var \OC\DB\Adapter $adapter
57
-	 */
58
-	protected $adapter;
59
-
60
-	protected $lockedTable = null;
61
-
62
-	public function connect() {
63
-		try {
64
-			return parent::connect();
65
-		} catch (DBALException $e) {
66
-			// throw a new exception to prevent leaking info from the stacktrace
67
-			throw new DBALException('Failed to connect to the database: ' . $e->getMessage(), $e->getCode());
68
-		}
69
-	}
70
-
71
-	/**
72
-	 * Returns a QueryBuilder for the connection.
73
-	 *
74
-	 * @return \OCP\DB\QueryBuilder\IQueryBuilder
75
-	 */
76
-	public function getQueryBuilder() {
77
-		return new QueryBuilder(
78
-			$this,
79
-			\OC::$server->getSystemConfig(),
80
-			\OC::$server->getLogger()
81
-		);
82
-	}
83
-
84
-	/**
85
-	 * Gets the QueryBuilder for the connection.
86
-	 *
87
-	 * @return \Doctrine\DBAL\Query\QueryBuilder
88
-	 * @deprecated please use $this->getQueryBuilder() instead
89
-	 */
90
-	public function createQueryBuilder() {
91
-		$backtrace = $this->getCallerBacktrace();
92
-		\OC::$server->getLogger()->debug('Doctrine QueryBuilder retrieved in {backtrace}', ['app' => 'core', 'backtrace' => $backtrace]);
93
-		return parent::createQueryBuilder();
94
-	}
95
-
96
-	/**
97
-	 * Gets the ExpressionBuilder for the connection.
98
-	 *
99
-	 * @return \Doctrine\DBAL\Query\Expression\ExpressionBuilder
100
-	 * @deprecated please use $this->getQueryBuilder()->expr() instead
101
-	 */
102
-	public function getExpressionBuilder() {
103
-		$backtrace = $this->getCallerBacktrace();
104
-		\OC::$server->getLogger()->debug('Doctrine ExpressionBuilder retrieved in {backtrace}', ['app' => 'core', 'backtrace' => $backtrace]);
105
-		return parent::getExpressionBuilder();
106
-	}
107
-
108
-	/**
109
-	 * Get the file and line that called the method where `getCallerBacktrace()` was used
110
-	 *
111
-	 * @return string
112
-	 */
113
-	protected function getCallerBacktrace() {
114
-		$traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
115
-
116
-		// 0 is the method where we use `getCallerBacktrace`
117
-		// 1 is the target method which uses the method we want to log
118
-		if (isset($traces[1])) {
119
-			return $traces[1]['file'] . ':' . $traces[1]['line'];
120
-		}
121
-
122
-		return '';
123
-	}
124
-
125
-	/**
126
-	 * @return string
127
-	 */
128
-	public function getPrefix() {
129
-		return $this->tablePrefix;
130
-	}
131
-
132
-	/**
133
-	 * Initializes a new instance of the Connection class.
134
-	 *
135
-	 * @param array $params  The connection parameters.
136
-	 * @param \Doctrine\DBAL\Driver $driver
137
-	 * @param \Doctrine\DBAL\Configuration $config
138
-	 * @param \Doctrine\Common\EventManager $eventManager
139
-	 * @throws \Exception
140
-	 */
141
-	public function __construct(array $params, Driver $driver, Configuration $config = null,
142
-		EventManager $eventManager = null)
143
-	{
144
-		if (!isset($params['adapter'])) {
145
-			throw new \Exception('adapter not set');
146
-		}
147
-		if (!isset($params['tablePrefix'])) {
148
-			throw new \Exception('tablePrefix not set');
149
-		}
150
-		parent::__construct($params, $driver, $config, $eventManager);
151
-		$this->adapter = new $params['adapter']($this);
152
-		$this->tablePrefix = $params['tablePrefix'];
153
-	}
154
-
155
-	/**
156
-	 * Prepares an SQL statement.
157
-	 *
158
-	 * @param string $statement The SQL statement to prepare.
159
-	 * @param int $limit
160
-	 * @param int $offset
161
-	 * @return \Doctrine\DBAL\Driver\Statement The prepared statement.
162
-	 */
163
-	public function prepare($statement, $limit=null, $offset=null) {
164
-		if ($limit === -1) {
165
-			$limit = null;
166
-		}
167
-		if (!is_null($limit)) {
168
-			$platform = $this->getDatabasePlatform();
169
-			$statement = $platform->modifyLimitQuery($statement, $limit, $offset);
170
-		}
171
-		$statement = $this->replaceTablePrefix($statement);
172
-		$statement = $this->adapter->fixupStatement($statement);
173
-
174
-		return parent::prepare($statement);
175
-	}
176
-
177
-	/**
178
-	 * Executes an, optionally parametrized, SQL query.
179
-	 *
180
-	 * If the query is parametrized, a prepared statement is used.
181
-	 * If an SQLLogger is configured, the execution is logged.
182
-	 *
183
-	 * @param string                                      $query  The SQL query to execute.
184
-	 * @param array                                       $params The parameters to bind to the query, if any.
185
-	 * @param array                                       $types  The types the previous parameters are in.
186
-	 * @param \Doctrine\DBAL\Cache\QueryCacheProfile|null $qcp    The query cache profile, optional.
187
-	 *
188
-	 * @return \Doctrine\DBAL\Driver\Statement The executed statement.
189
-	 *
190
-	 * @throws \Doctrine\DBAL\DBALException
191
-	 */
192
-	public function executeQuery($query, array $params = [], $types = [], QueryCacheProfile $qcp = null)
193
-	{
194
-		$query = $this->replaceTablePrefix($query);
195
-		$query = $this->adapter->fixupStatement($query);
196
-		return parent::executeQuery($query, $params, $types, $qcp);
197
-	}
198
-
199
-	/**
200
-	 * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters
201
-	 * and returns the number of affected rows.
202
-	 *
203
-	 * This method supports PDO binding types as well as DBAL mapping types.
204
-	 *
205
-	 * @param string $query  The SQL query.
206
-	 * @param array  $params The query parameters.
207
-	 * @param array  $types  The parameter types.
208
-	 *
209
-	 * @return integer The number of affected rows.
210
-	 *
211
-	 * @throws \Doctrine\DBAL\DBALException
212
-	 */
213
-	public function executeUpdate($query, array $params = [], array $types = [])
214
-	{
215
-		$query = $this->replaceTablePrefix($query);
216
-		$query = $this->adapter->fixupStatement($query);
217
-		return parent::executeUpdate($query, $params, $types);
218
-	}
219
-
220
-	/**
221
-	 * Returns the ID of the last inserted row, or the last value from a sequence object,
222
-	 * depending on the underlying driver.
223
-	 *
224
-	 * Note: This method may not return a meaningful or consistent result across different drivers,
225
-	 * because the underlying database may not even support the notion of AUTO_INCREMENT/IDENTITY
226
-	 * columns or sequences.
227
-	 *
228
-	 * @param string $seqName Name of the sequence object from which the ID should be returned.
229
-	 * @return string A string representation of the last inserted ID.
230
-	 */
231
-	public function lastInsertId($seqName = null) {
232
-		if ($seqName) {
233
-			$seqName = $this->replaceTablePrefix($seqName);
234
-		}
235
-		return $this->adapter->lastInsertId($seqName);
236
-	}
237
-
238
-	// internal use
239
-	public function realLastInsertId($seqName = null) {
240
-		return parent::lastInsertId($seqName);
241
-	}
242
-
243
-	/**
244
-	 * Insert a row if the matching row does not exists. To accomplish proper race condition avoidance
245
-	 * it is needed that there is also a unique constraint on the values. Then this method will
246
-	 * catch the exception and return 0.
247
-	 *
248
-	 * @param string $table The table name (will replace *PREFIX* with the actual prefix)
249
-	 * @param array $input data that should be inserted into the table  (column name => value)
250
-	 * @param array|null $compare List of values that should be checked for "if not exists"
251
-	 *				If this is null or an empty array, all keys of $input will be compared
252
-	 *				Please note: text fields (clob) must not be used in the compare array
253
-	 * @return int number of inserted rows
254
-	 * @throws \Doctrine\DBAL\DBALException
255
-	 * @deprecated 15.0.0 - use unique index and "try { $db->insert() } catch (UniqueConstraintViolationException $e) {}" instead, because it is more reliable and does not have the risk for deadlocks - see https://github.com/nextcloud/server/pull/12371
256
-	 */
257
-	public function insertIfNotExist($table, $input, array $compare = null) {
258
-		return $this->adapter->insertIfNotExist($table, $input, $compare);
259
-	}
260
-
261
-	public function insertIgnoreConflict(string $table, array $values) : int {
262
-		return $this->adapter->insertIgnoreConflict($table, $values);
263
-	}
264
-
265
-	private function getType($value) {
266
-		if (is_bool($value)) {
267
-			return IQueryBuilder::PARAM_BOOL;
268
-		} else if (is_int($value)) {
269
-			return IQueryBuilder::PARAM_INT;
270
-		} else {
271
-			return IQueryBuilder::PARAM_STR;
272
-		}
273
-	}
274
-
275
-	/**
276
-	 * Insert or update a row value
277
-	 *
278
-	 * @param string $table
279
-	 * @param array $keys (column name => value)
280
-	 * @param array $values (column name => value)
281
-	 * @param array $updatePreconditionValues ensure values match preconditions (column name => value)
282
-	 * @return int number of new rows
283
-	 * @throws \Doctrine\DBAL\DBALException
284
-	 * @throws PreConditionNotMetException
285
-	 * @suppress SqlInjectionChecker
286
-	 */
287
-	public function setValues($table, array $keys, array $values, array $updatePreconditionValues = []) {
288
-		try {
289
-			$insertQb = $this->getQueryBuilder();
290
-			$insertQb->insert($table)
291
-				->values(
292
-					array_map(function ($value) use ($insertQb) {
293
-						return $insertQb->createNamedParameter($value, $this->getType($value));
294
-					}, array_merge($keys, $values))
295
-				);
296
-			return $insertQb->execute();
297
-		} catch (ConstraintViolationException $e) {
298
-			// value already exists, try update
299
-			$updateQb = $this->getQueryBuilder();
300
-			$updateQb->update($table);
301
-			foreach ($values as $name => $value) {
302
-				$updateQb->set($name, $updateQb->createNamedParameter($value, $this->getType($value)));
303
-			}
304
-			$where = $updateQb->expr()->andX();
305
-			$whereValues = array_merge($keys, $updatePreconditionValues);
306
-			foreach ($whereValues as $name => $value) {
307
-				$where->add($updateQb->expr()->eq(
308
-					$name,
309
-					$updateQb->createNamedParameter($value, $this->getType($value)),
310
-					$this->getType($value)
311
-				));
312
-			}
313
-			$updateQb->where($where);
314
-			$affected = $updateQb->execute();
315
-
316
-			if ($affected === 0 && !empty($updatePreconditionValues)) {
317
-				throw new PreConditionNotMetException();
318
-			}
319
-
320
-			return 0;
321
-		}
322
-	}
323
-
324
-	/**
325
-	 * Create an exclusive read+write lock on a table
326
-	 *
327
-	 * @param string $tableName
328
-	 * @throws \BadMethodCallException When trying to acquire a second lock
329
-	 * @since 9.1.0
330
-	 */
331
-	public function lockTable($tableName) {
332
-		if ($this->lockedTable !== null) {
333
-			throw new \BadMethodCallException('Can not lock a new table until the previous lock is released.');
334
-		}
335
-
336
-		$tableName = $this->tablePrefix . $tableName;
337
-		$this->lockedTable = $tableName;
338
-		$this->adapter->lockTable($tableName);
339
-	}
340
-
341
-	/**
342
-	 * Release a previous acquired lock again
343
-	 *
344
-	 * @since 9.1.0
345
-	 */
346
-	public function unlockTable() {
347
-		$this->adapter->unlockTable();
348
-		$this->lockedTable = null;
349
-	}
350
-
351
-	/**
352
-	 * returns the error code and message as a string for logging
353
-	 * works with DoctrineException
354
-	 * @return string
355
-	 */
356
-	public function getError() {
357
-		$msg = $this->errorCode() . ': ';
358
-		$errorInfo = $this->errorInfo();
359
-		if (is_array($errorInfo)) {
360
-			$msg .= 'SQLSTATE = '.$errorInfo[0] . ', ';
361
-			$msg .= 'Driver Code = '.$errorInfo[1] . ', ';
362
-			$msg .= 'Driver Message = '.$errorInfo[2];
363
-		}
364
-		return $msg;
365
-	}
366
-
367
-	/**
368
-	 * Drop a table from the database if it exists
369
-	 *
370
-	 * @param string $table table name without the prefix
371
-	 */
372
-	public function dropTable($table) {
373
-		$table = $this->tablePrefix . trim($table);
374
-		$schema = $this->getSchemaManager();
375
-		if($schema->tablesExist([$table])) {
376
-			$schema->dropTable($table);
377
-		}
378
-	}
379
-
380
-	/**
381
-	 * Check if a table exists
382
-	 *
383
-	 * @param string $table table name without the prefix
384
-	 * @return bool
385
-	 */
386
-	public function tableExists($table) {
387
-		$table = $this->tablePrefix . trim($table);
388
-		$schema = $this->getSchemaManager();
389
-		return $schema->tablesExist([$table]);
390
-	}
391
-
392
-	// internal use
393
-	/**
394
-	 * @param string $statement
395
-	 * @return string
396
-	 */
397
-	protected function replaceTablePrefix($statement) {
398
-		return str_replace( '*PREFIX*', $this->tablePrefix, $statement );
399
-	}
400
-
401
-	/**
402
-	 * Check if a transaction is active
403
-	 *
404
-	 * @return bool
405
-	 * @since 8.2.0
406
-	 */
407
-	public function inTransaction() {
408
-		return $this->getTransactionNestingLevel() > 0;
409
-	}
410
-
411
-	/**
412
-	 * Escape a parameter to be used in a LIKE query
413
-	 *
414
-	 * @param string $param
415
-	 * @return string
416
-	 */
417
-	public function escapeLikeParameter($param) {
418
-		return addcslashes($param, '\\_%');
419
-	}
420
-
421
-	/**
422
-	 * Check whether or not the current database support 4byte wide unicode
423
-	 *
424
-	 * @return bool
425
-	 * @since 11.0.0
426
-	 */
427
-	public function supports4ByteText() {
428
-		if (!$this->getDatabasePlatform() instanceof MySqlPlatform) {
429
-			return true;
430
-		}
431
-		return $this->getParams()['charset'] === 'utf8mb4';
432
-	}
433
-
434
-
435
-	/**
436
-	 * Create the schema of the connected database
437
-	 *
438
-	 * @return Schema
439
-	 */
440
-	public function createSchema() {
441
-		$schemaManager = new MDB2SchemaManager($this);
442
-		$migrator = $schemaManager->getMigrator();
443
-		return $migrator->createSchema();
444
-	}
445
-
446
-	/**
447
-	 * Migrate the database to the given schema
448
-	 *
449
-	 * @param Schema $toSchema
450
-	 */
451
-	public function migrateToSchema(Schema $toSchema) {
452
-		$schemaManager = new MDB2SchemaManager($this);
453
-		$migrator = $schemaManager->getMigrator();
454
-		$migrator->migrate($toSchema);
455
-	}
50
+    /**
51
+     * @var string $tablePrefix
52
+     */
53
+    protected $tablePrefix;
54
+
55
+    /**
56
+     * @var \OC\DB\Adapter $adapter
57
+     */
58
+    protected $adapter;
59
+
60
+    protected $lockedTable = null;
61
+
62
+    public function connect() {
63
+        try {
64
+            return parent::connect();
65
+        } catch (DBALException $e) {
66
+            // throw a new exception to prevent leaking info from the stacktrace
67
+            throw new DBALException('Failed to connect to the database: ' . $e->getMessage(), $e->getCode());
68
+        }
69
+    }
70
+
71
+    /**
72
+     * Returns a QueryBuilder for the connection.
73
+     *
74
+     * @return \OCP\DB\QueryBuilder\IQueryBuilder
75
+     */
76
+    public function getQueryBuilder() {
77
+        return new QueryBuilder(
78
+            $this,
79
+            \OC::$server->getSystemConfig(),
80
+            \OC::$server->getLogger()
81
+        );
82
+    }
83
+
84
+    /**
85
+     * Gets the QueryBuilder for the connection.
86
+     *
87
+     * @return \Doctrine\DBAL\Query\QueryBuilder
88
+     * @deprecated please use $this->getQueryBuilder() instead
89
+     */
90
+    public function createQueryBuilder() {
91
+        $backtrace = $this->getCallerBacktrace();
92
+        \OC::$server->getLogger()->debug('Doctrine QueryBuilder retrieved in {backtrace}', ['app' => 'core', 'backtrace' => $backtrace]);
93
+        return parent::createQueryBuilder();
94
+    }
95
+
96
+    /**
97
+     * Gets the ExpressionBuilder for the connection.
98
+     *
99
+     * @return \Doctrine\DBAL\Query\Expression\ExpressionBuilder
100
+     * @deprecated please use $this->getQueryBuilder()->expr() instead
101
+     */
102
+    public function getExpressionBuilder() {
103
+        $backtrace = $this->getCallerBacktrace();
104
+        \OC::$server->getLogger()->debug('Doctrine ExpressionBuilder retrieved in {backtrace}', ['app' => 'core', 'backtrace' => $backtrace]);
105
+        return parent::getExpressionBuilder();
106
+    }
107
+
108
+    /**
109
+     * Get the file and line that called the method where `getCallerBacktrace()` was used
110
+     *
111
+     * @return string
112
+     */
113
+    protected function getCallerBacktrace() {
114
+        $traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
115
+
116
+        // 0 is the method where we use `getCallerBacktrace`
117
+        // 1 is the target method which uses the method we want to log
118
+        if (isset($traces[1])) {
119
+            return $traces[1]['file'] . ':' . $traces[1]['line'];
120
+        }
121
+
122
+        return '';
123
+    }
124
+
125
+    /**
126
+     * @return string
127
+     */
128
+    public function getPrefix() {
129
+        return $this->tablePrefix;
130
+    }
131
+
132
+    /**
133
+     * Initializes a new instance of the Connection class.
134
+     *
135
+     * @param array $params  The connection parameters.
136
+     * @param \Doctrine\DBAL\Driver $driver
137
+     * @param \Doctrine\DBAL\Configuration $config
138
+     * @param \Doctrine\Common\EventManager $eventManager
139
+     * @throws \Exception
140
+     */
141
+    public function __construct(array $params, Driver $driver, Configuration $config = null,
142
+        EventManager $eventManager = null)
143
+    {
144
+        if (!isset($params['adapter'])) {
145
+            throw new \Exception('adapter not set');
146
+        }
147
+        if (!isset($params['tablePrefix'])) {
148
+            throw new \Exception('tablePrefix not set');
149
+        }
150
+        parent::__construct($params, $driver, $config, $eventManager);
151
+        $this->adapter = new $params['adapter']($this);
152
+        $this->tablePrefix = $params['tablePrefix'];
153
+    }
154
+
155
+    /**
156
+     * Prepares an SQL statement.
157
+     *
158
+     * @param string $statement The SQL statement to prepare.
159
+     * @param int $limit
160
+     * @param int $offset
161
+     * @return \Doctrine\DBAL\Driver\Statement The prepared statement.
162
+     */
163
+    public function prepare($statement, $limit=null, $offset=null) {
164
+        if ($limit === -1) {
165
+            $limit = null;
166
+        }
167
+        if (!is_null($limit)) {
168
+            $platform = $this->getDatabasePlatform();
169
+            $statement = $platform->modifyLimitQuery($statement, $limit, $offset);
170
+        }
171
+        $statement = $this->replaceTablePrefix($statement);
172
+        $statement = $this->adapter->fixupStatement($statement);
173
+
174
+        return parent::prepare($statement);
175
+    }
176
+
177
+    /**
178
+     * Executes an, optionally parametrized, SQL query.
179
+     *
180
+     * If the query is parametrized, a prepared statement is used.
181
+     * If an SQLLogger is configured, the execution is logged.
182
+     *
183
+     * @param string                                      $query  The SQL query to execute.
184
+     * @param array                                       $params The parameters to bind to the query, if any.
185
+     * @param array                                       $types  The types the previous parameters are in.
186
+     * @param \Doctrine\DBAL\Cache\QueryCacheProfile|null $qcp    The query cache profile, optional.
187
+     *
188
+     * @return \Doctrine\DBAL\Driver\Statement The executed statement.
189
+     *
190
+     * @throws \Doctrine\DBAL\DBALException
191
+     */
192
+    public function executeQuery($query, array $params = [], $types = [], QueryCacheProfile $qcp = null)
193
+    {
194
+        $query = $this->replaceTablePrefix($query);
195
+        $query = $this->adapter->fixupStatement($query);
196
+        return parent::executeQuery($query, $params, $types, $qcp);
197
+    }
198
+
199
+    /**
200
+     * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters
201
+     * and returns the number of affected rows.
202
+     *
203
+     * This method supports PDO binding types as well as DBAL mapping types.
204
+     *
205
+     * @param string $query  The SQL query.
206
+     * @param array  $params The query parameters.
207
+     * @param array  $types  The parameter types.
208
+     *
209
+     * @return integer The number of affected rows.
210
+     *
211
+     * @throws \Doctrine\DBAL\DBALException
212
+     */
213
+    public function executeUpdate($query, array $params = [], array $types = [])
214
+    {
215
+        $query = $this->replaceTablePrefix($query);
216
+        $query = $this->adapter->fixupStatement($query);
217
+        return parent::executeUpdate($query, $params, $types);
218
+    }
219
+
220
+    /**
221
+     * Returns the ID of the last inserted row, or the last value from a sequence object,
222
+     * depending on the underlying driver.
223
+     *
224
+     * Note: This method may not return a meaningful or consistent result across different drivers,
225
+     * because the underlying database may not even support the notion of AUTO_INCREMENT/IDENTITY
226
+     * columns or sequences.
227
+     *
228
+     * @param string $seqName Name of the sequence object from which the ID should be returned.
229
+     * @return string A string representation of the last inserted ID.
230
+     */
231
+    public function lastInsertId($seqName = null) {
232
+        if ($seqName) {
233
+            $seqName = $this->replaceTablePrefix($seqName);
234
+        }
235
+        return $this->adapter->lastInsertId($seqName);
236
+    }
237
+
238
+    // internal use
239
+    public function realLastInsertId($seqName = null) {
240
+        return parent::lastInsertId($seqName);
241
+    }
242
+
243
+    /**
244
+     * Insert a row if the matching row does not exists. To accomplish proper race condition avoidance
245
+     * it is needed that there is also a unique constraint on the values. Then this method will
246
+     * catch the exception and return 0.
247
+     *
248
+     * @param string $table The table name (will replace *PREFIX* with the actual prefix)
249
+     * @param array $input data that should be inserted into the table  (column name => value)
250
+     * @param array|null $compare List of values that should be checked for "if not exists"
251
+     *				If this is null or an empty array, all keys of $input will be compared
252
+     *				Please note: text fields (clob) must not be used in the compare array
253
+     * @return int number of inserted rows
254
+     * @throws \Doctrine\DBAL\DBALException
255
+     * @deprecated 15.0.0 - use unique index and "try { $db->insert() } catch (UniqueConstraintViolationException $e) {}" instead, because it is more reliable and does not have the risk for deadlocks - see https://github.com/nextcloud/server/pull/12371
256
+     */
257
+    public function insertIfNotExist($table, $input, array $compare = null) {
258
+        return $this->adapter->insertIfNotExist($table, $input, $compare);
259
+    }
260
+
261
+    public function insertIgnoreConflict(string $table, array $values) : int {
262
+        return $this->adapter->insertIgnoreConflict($table, $values);
263
+    }
264
+
265
+    private function getType($value) {
266
+        if (is_bool($value)) {
267
+            return IQueryBuilder::PARAM_BOOL;
268
+        } else if (is_int($value)) {
269
+            return IQueryBuilder::PARAM_INT;
270
+        } else {
271
+            return IQueryBuilder::PARAM_STR;
272
+        }
273
+    }
274
+
275
+    /**
276
+     * Insert or update a row value
277
+     *
278
+     * @param string $table
279
+     * @param array $keys (column name => value)
280
+     * @param array $values (column name => value)
281
+     * @param array $updatePreconditionValues ensure values match preconditions (column name => value)
282
+     * @return int number of new rows
283
+     * @throws \Doctrine\DBAL\DBALException
284
+     * @throws PreConditionNotMetException
285
+     * @suppress SqlInjectionChecker
286
+     */
287
+    public function setValues($table, array $keys, array $values, array $updatePreconditionValues = []) {
288
+        try {
289
+            $insertQb = $this->getQueryBuilder();
290
+            $insertQb->insert($table)
291
+                ->values(
292
+                    array_map(function ($value) use ($insertQb) {
293
+                        return $insertQb->createNamedParameter($value, $this->getType($value));
294
+                    }, array_merge($keys, $values))
295
+                );
296
+            return $insertQb->execute();
297
+        } catch (ConstraintViolationException $e) {
298
+            // value already exists, try update
299
+            $updateQb = $this->getQueryBuilder();
300
+            $updateQb->update($table);
301
+            foreach ($values as $name => $value) {
302
+                $updateQb->set($name, $updateQb->createNamedParameter($value, $this->getType($value)));
303
+            }
304
+            $where = $updateQb->expr()->andX();
305
+            $whereValues = array_merge($keys, $updatePreconditionValues);
306
+            foreach ($whereValues as $name => $value) {
307
+                $where->add($updateQb->expr()->eq(
308
+                    $name,
309
+                    $updateQb->createNamedParameter($value, $this->getType($value)),
310
+                    $this->getType($value)
311
+                ));
312
+            }
313
+            $updateQb->where($where);
314
+            $affected = $updateQb->execute();
315
+
316
+            if ($affected === 0 && !empty($updatePreconditionValues)) {
317
+                throw new PreConditionNotMetException();
318
+            }
319
+
320
+            return 0;
321
+        }
322
+    }
323
+
324
+    /**
325
+     * Create an exclusive read+write lock on a table
326
+     *
327
+     * @param string $tableName
328
+     * @throws \BadMethodCallException When trying to acquire a second lock
329
+     * @since 9.1.0
330
+     */
331
+    public function lockTable($tableName) {
332
+        if ($this->lockedTable !== null) {
333
+            throw new \BadMethodCallException('Can not lock a new table until the previous lock is released.');
334
+        }
335
+
336
+        $tableName = $this->tablePrefix . $tableName;
337
+        $this->lockedTable = $tableName;
338
+        $this->adapter->lockTable($tableName);
339
+    }
340
+
341
+    /**
342
+     * Release a previous acquired lock again
343
+     *
344
+     * @since 9.1.0
345
+     */
346
+    public function unlockTable() {
347
+        $this->adapter->unlockTable();
348
+        $this->lockedTable = null;
349
+    }
350
+
351
+    /**
352
+     * returns the error code and message as a string for logging
353
+     * works with DoctrineException
354
+     * @return string
355
+     */
356
+    public function getError() {
357
+        $msg = $this->errorCode() . ': ';
358
+        $errorInfo = $this->errorInfo();
359
+        if (is_array($errorInfo)) {
360
+            $msg .= 'SQLSTATE = '.$errorInfo[0] . ', ';
361
+            $msg .= 'Driver Code = '.$errorInfo[1] . ', ';
362
+            $msg .= 'Driver Message = '.$errorInfo[2];
363
+        }
364
+        return $msg;
365
+    }
366
+
367
+    /**
368
+     * Drop a table from the database if it exists
369
+     *
370
+     * @param string $table table name without the prefix
371
+     */
372
+    public function dropTable($table) {
373
+        $table = $this->tablePrefix . trim($table);
374
+        $schema = $this->getSchemaManager();
375
+        if($schema->tablesExist([$table])) {
376
+            $schema->dropTable($table);
377
+        }
378
+    }
379
+
380
+    /**
381
+     * Check if a table exists
382
+     *
383
+     * @param string $table table name without the prefix
384
+     * @return bool
385
+     */
386
+    public function tableExists($table) {
387
+        $table = $this->tablePrefix . trim($table);
388
+        $schema = $this->getSchemaManager();
389
+        return $schema->tablesExist([$table]);
390
+    }
391
+
392
+    // internal use
393
+    /**
394
+     * @param string $statement
395
+     * @return string
396
+     */
397
+    protected function replaceTablePrefix($statement) {
398
+        return str_replace( '*PREFIX*', $this->tablePrefix, $statement );
399
+    }
400
+
401
+    /**
402
+     * Check if a transaction is active
403
+     *
404
+     * @return bool
405
+     * @since 8.2.0
406
+     */
407
+    public function inTransaction() {
408
+        return $this->getTransactionNestingLevel() > 0;
409
+    }
410
+
411
+    /**
412
+     * Escape a parameter to be used in a LIKE query
413
+     *
414
+     * @param string $param
415
+     * @return string
416
+     */
417
+    public function escapeLikeParameter($param) {
418
+        return addcslashes($param, '\\_%');
419
+    }
420
+
421
+    /**
422
+     * Check whether or not the current database support 4byte wide unicode
423
+     *
424
+     * @return bool
425
+     * @since 11.0.0
426
+     */
427
+    public function supports4ByteText() {
428
+        if (!$this->getDatabasePlatform() instanceof MySqlPlatform) {
429
+            return true;
430
+        }
431
+        return $this->getParams()['charset'] === 'utf8mb4';
432
+    }
433
+
434
+
435
+    /**
436
+     * Create the schema of the connected database
437
+     *
438
+     * @return Schema
439
+     */
440
+    public function createSchema() {
441
+        $schemaManager = new MDB2SchemaManager($this);
442
+        $migrator = $schemaManager->getMigrator();
443
+        return $migrator->createSchema();
444
+    }
445
+
446
+    /**
447
+     * Migrate the database to the given schema
448
+     *
449
+     * @param Schema $toSchema
450
+     */
451
+    public function migrateToSchema(Schema $toSchema) {
452
+        $schemaManager = new MDB2SchemaManager($this);
453
+        $migrator = $schemaManager->getMigrator();
454
+        $migrator->migrate($toSchema);
455
+    }
456 456
 }
Please login to merge, or discard this patch.
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -64,7 +64,7 @@  discard block
 block discarded – undo
64 64
 			return parent::connect();
65 65
 		} catch (DBALException $e) {
66 66
 			// throw a new exception to prevent leaking info from the stacktrace
67
-			throw new DBALException('Failed to connect to the database: ' . $e->getMessage(), $e->getCode());
67
+			throw new DBALException('Failed to connect to the database: '.$e->getMessage(), $e->getCode());
68 68
 		}
69 69
 	}
70 70
 
@@ -116,7 +116,7 @@  discard block
 block discarded – undo
116 116
 		// 0 is the method where we use `getCallerBacktrace`
117 117
 		// 1 is the target method which uses the method we want to log
118 118
 		if (isset($traces[1])) {
119
-			return $traces[1]['file'] . ':' . $traces[1]['line'];
119
+			return $traces[1]['file'].':'.$traces[1]['line'];
120 120
 		}
121 121
 
122 122
 		return '';
@@ -160,7 +160,7 @@  discard block
 block discarded – undo
160 160
 	 * @param int $offset
161 161
 	 * @return \Doctrine\DBAL\Driver\Statement The prepared statement.
162 162
 	 */
163
-	public function prepare($statement, $limit=null, $offset=null) {
163
+	public function prepare($statement, $limit = null, $offset = null) {
164 164
 		if ($limit === -1) {
165 165
 			$limit = null;
166 166
 		}
@@ -289,7 +289,7 @@  discard block
 block discarded – undo
289 289
 			$insertQb = $this->getQueryBuilder();
290 290
 			$insertQb->insert($table)
291 291
 				->values(
292
-					array_map(function ($value) use ($insertQb) {
292
+					array_map(function($value) use ($insertQb) {
293 293
 						return $insertQb->createNamedParameter($value, $this->getType($value));
294 294
 					}, array_merge($keys, $values))
295 295
 				);
@@ -333,7 +333,7 @@  discard block
 block discarded – undo
333 333
 			throw new \BadMethodCallException('Can not lock a new table until the previous lock is released.');
334 334
 		}
335 335
 
336
-		$tableName = $this->tablePrefix . $tableName;
336
+		$tableName = $this->tablePrefix.$tableName;
337 337
 		$this->lockedTable = $tableName;
338 338
 		$this->adapter->lockTable($tableName);
339 339
 	}
@@ -354,11 +354,11 @@  discard block
 block discarded – undo
354 354
 	 * @return string
355 355
 	 */
356 356
 	public function getError() {
357
-		$msg = $this->errorCode() . ': ';
357
+		$msg = $this->errorCode().': ';
358 358
 		$errorInfo = $this->errorInfo();
359 359
 		if (is_array($errorInfo)) {
360
-			$msg .= 'SQLSTATE = '.$errorInfo[0] . ', ';
361
-			$msg .= 'Driver Code = '.$errorInfo[1] . ', ';
360
+			$msg .= 'SQLSTATE = '.$errorInfo[0].', ';
361
+			$msg .= 'Driver Code = '.$errorInfo[1].', ';
362 362
 			$msg .= 'Driver Message = '.$errorInfo[2];
363 363
 		}
364 364
 		return $msg;
@@ -370,9 +370,9 @@  discard block
 block discarded – undo
370 370
 	 * @param string $table table name without the prefix
371 371
 	 */
372 372
 	public function dropTable($table) {
373
-		$table = $this->tablePrefix . trim($table);
373
+		$table = $this->tablePrefix.trim($table);
374 374
 		$schema = $this->getSchemaManager();
375
-		if($schema->tablesExist([$table])) {
375
+		if ($schema->tablesExist([$table])) {
376 376
 			$schema->dropTable($table);
377 377
 		}
378 378
 	}
@@ -384,7 +384,7 @@  discard block
 block discarded – undo
384 384
 	 * @return bool
385 385
 	 */
386 386
 	public function tableExists($table) {
387
-		$table = $this->tablePrefix . trim($table);
387
+		$table = $this->tablePrefix.trim($table);
388 388
 		$schema = $this->getSchemaManager();
389 389
 		return $schema->tablesExist([$table]);
390 390
 	}
@@ -395,7 +395,7 @@  discard block
 block discarded – undo
395 395
 	 * @return string
396 396
 	 */
397 397
 	protected function replaceTablePrefix($statement) {
398
-		return str_replace( '*PREFIX*', $this->tablePrefix, $statement );
398
+		return str_replace('*PREFIX*', $this->tablePrefix, $statement);
399 399
 	}
400 400
 
401 401
 	/**
Please login to merge, or discard this patch.
lib/private/DB/MigrationService.php 2 patches
Indentation   +523 added lines, -523 removed lines patch added patch discarded remove patch
@@ -45,527 +45,527 @@
 block discarded – undo
45 45
 
46 46
 class MigrationService {
47 47
 
48
-	/** @var boolean */
49
-	private $migrationTableCreated;
50
-	/** @var array */
51
-	private $migrations;
52
-	/** @var IOutput */
53
-	private $output;
54
-	/** @var Connection */
55
-	private $connection;
56
-	/** @var string */
57
-	private $appName;
58
-	/** @var bool */
59
-	private $checkOracle;
60
-
61
-	/**
62
-	 * MigrationService constructor.
63
-	 *
64
-	 * @param $appName
65
-	 * @param IDBConnection $connection
66
-	 * @param AppLocator $appLocator
67
-	 * @param IOutput|null $output
68
-	 * @throws \Exception
69
-	 */
70
-	public function __construct($appName, IDBConnection $connection, IOutput $output = null, AppLocator $appLocator = null) {
71
-		$this->appName = $appName;
72
-		$this->connection = $connection;
73
-		$this->output = $output;
74
-		if (null === $this->output) {
75
-			$this->output = new SimpleOutput(\OC::$server->getLogger(), $appName);
76
-		}
77
-
78
-		if ($appName === 'core') {
79
-			$this->migrationsPath = \OC::$SERVERROOT . '/core/Migrations';
80
-			$this->migrationsNamespace = 'OC\\Core\\Migrations';
81
-			$this->checkOracle = true;
82
-		} else {
83
-			if (null === $appLocator) {
84
-				$appLocator = new AppLocator();
85
-			}
86
-			$appPath = $appLocator->getAppPath($appName);
87
-			$namespace = App::buildAppNamespace($appName);
88
-			$this->migrationsPath = "$appPath/lib/Migration";
89
-			$this->migrationsNamespace = $namespace . '\\Migration';
90
-
91
-			$infoParser = new InfoParser();
92
-			$info = $infoParser->parse($appPath . '/appinfo/info.xml');
93
-			if (!isset($info['dependencies']['database'])) {
94
-				$this->checkOracle = true;
95
-			} else {
96
-				$this->checkOracle = false;
97
-				foreach ($info['dependencies']['database'] as $database) {
98
-					if (\is_string($database) && $database === 'oci') {
99
-						$this->checkOracle = true;
100
-					} else if (\is_array($database) && isset($database['@value']) && $database['@value'] === 'oci') {
101
-						$this->checkOracle = true;
102
-					}
103
-				}
104
-			}
105
-		}
106
-	}
107
-
108
-	/**
109
-	 * Returns the name of the app for which this migration is executed
110
-	 *
111
-	 * @return string
112
-	 */
113
-	public function getApp() {
114
-		return $this->appName;
115
-	}
116
-
117
-	/**
118
-	 * @return bool
119
-	 * @codeCoverageIgnore - this will implicitly tested on installation
120
-	 */
121
-	private function createMigrationTable() {
122
-		if ($this->migrationTableCreated) {
123
-			return false;
124
-		}
125
-
126
-		$schema = new SchemaWrapper($this->connection);
127
-
128
-		/**
129
-		 * We drop the table when it has different columns or the definition does not
130
-		 * match. E.g. ownCloud uses a length of 177 for app and 14 for version.
131
-		 */
132
-		try {
133
-			$table = $schema->getTable('migrations');
134
-			$columns = $table->getColumns();
135
-
136
-			if (count($columns) === 2) {
137
-				try {
138
-					$column = $table->getColumn('app');
139
-					$schemaMismatch = $column->getLength() !== 255;
140
-
141
-					if (!$schemaMismatch) {
142
-						$column = $table->getColumn('version');
143
-						$schemaMismatch = $column->getLength() !== 255;
144
-					}
145
-				} catch (SchemaException $e) {
146
-					// One of the columns is missing
147
-					$schemaMismatch = true;
148
-				}
149
-
150
-				if (!$schemaMismatch) {
151
-					// Table exists and schema matches: return back!
152
-					$this->migrationTableCreated = true;
153
-					return false;
154
-				}
155
-			}
156
-
157
-			// Drop the table, when it didn't match our expectations.
158
-			$this->connection->dropTable('migrations');
159
-
160
-			// Recreate the schema after the table was dropped.
161
-			$schema = new SchemaWrapper($this->connection);
162
-
163
-		} catch (SchemaException $e) {
164
-			// Table not found, no need to panic, we will create it.
165
-		}
166
-
167
-		$table = $schema->createTable('migrations');
168
-		$table->addColumn('app', Type::STRING, ['length' => 255]);
169
-		$table->addColumn('version', Type::STRING, ['length' => 255]);
170
-		$table->setPrimaryKey(['app', 'version']);
171
-
172
-		$this->connection->migrateToSchema($schema->getWrappedSchema());
173
-
174
-		$this->migrationTableCreated = true;
175
-
176
-		return true;
177
-	}
178
-
179
-	/**
180
-	 * Returns all versions which have already been applied
181
-	 *
182
-	 * @return string[]
183
-	 * @codeCoverageIgnore - no need to test this
184
-	 */
185
-	public function getMigratedVersions() {
186
-		$this->createMigrationTable();
187
-		$qb = $this->connection->getQueryBuilder();
188
-
189
-		$qb->select('version')
190
-			->from('migrations')
191
-			->where($qb->expr()->eq('app', $qb->createNamedParameter($this->getApp())))
192
-			->orderBy('version');
193
-
194
-		$result = $qb->execute();
195
-		$rows = $result->fetchAll(\PDO::FETCH_COLUMN);
196
-		$result->closeCursor();
197
-
198
-		return $rows;
199
-	}
200
-
201
-	/**
202
-	 * Returns all versions which are available in the migration folder
203
-	 *
204
-	 * @return array
205
-	 */
206
-	public function getAvailableVersions() {
207
-		$this->ensureMigrationsAreLoaded();
208
-		return array_map('strval', array_keys($this->migrations));
209
-	}
210
-
211
-	protected function findMigrations() {
212
-		$directory = realpath($this->migrationsPath);
213
-		if ($directory === false || !file_exists($directory) || !is_dir($directory)) {
214
-			return [];
215
-		}
216
-
217
-		$iterator = new \RegexIterator(
218
-			new \RecursiveIteratorIterator(
219
-				new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS),
220
-				\RecursiveIteratorIterator::LEAVES_ONLY
221
-			),
222
-			'#^.+\\/Version[^\\/]{1,255}\\.php$#i',
223
-			\RegexIterator::GET_MATCH);
224
-
225
-		$files = array_keys(iterator_to_array($iterator));
226
-		uasort($files, function ($a, $b) {
227
-			preg_match('/^Version(\d+)Date(\d+)\\.php$/', basename($a), $matchA);
228
-			preg_match('/^Version(\d+)Date(\d+)\\.php$/', basename($b), $matchB);
229
-			if (!empty($matchA) && !empty($matchB)) {
230
-				if ($matchA[1] !== $matchB[1]) {
231
-					return ($matchA[1] < $matchB[1]) ? -1 : 1;
232
-				}
233
-				return ($matchA[2] < $matchB[2]) ? -1 : 1;
234
-			}
235
-			return (basename($a) < basename($b)) ? -1 : 1;
236
-		});
237
-
238
-		$migrations = [];
239
-
240
-		foreach ($files as $file) {
241
-			$className = basename($file, '.php');
242
-			$version = (string) substr($className, 7);
243
-			if ($version === '0') {
244
-				throw new \InvalidArgumentException(
245
-					"Cannot load a migrations with the name '$version' because it is a reserved number"
246
-				);
247
-			}
248
-			$migrations[$version] = sprintf('%s\\%s', $this->migrationsNamespace, $className);
249
-		}
250
-
251
-		return $migrations;
252
-	}
253
-
254
-	/**
255
-	 * @param string $to
256
-	 * @return string[]
257
-	 */
258
-	private function getMigrationsToExecute($to) {
259
-		$knownMigrations = $this->getMigratedVersions();
260
-		$availableMigrations = $this->getAvailableVersions();
261
-
262
-		$toBeExecuted = [];
263
-		foreach ($availableMigrations as $v) {
264
-			if ($to !== 'latest' && $v > $to) {
265
-				continue;
266
-			}
267
-			if ($this->shallBeExecuted($v, $knownMigrations)) {
268
-				$toBeExecuted[] = $v;
269
-			}
270
-		}
271
-
272
-		return $toBeExecuted;
273
-	}
274
-
275
-	/**
276
-	 * @param string $m
277
-	 * @param string[] $knownMigrations
278
-	 * @return bool
279
-	 */
280
-	private function shallBeExecuted($m, $knownMigrations) {
281
-		if (in_array($m, $knownMigrations)) {
282
-			return false;
283
-		}
284
-
285
-		return true;
286
-	}
287
-
288
-	/**
289
-	 * @param string $version
290
-	 */
291
-	private function markAsExecuted($version) {
292
-		$this->connection->insertIfNotExist('*PREFIX*migrations', [
293
-			'app' => $this->appName,
294
-			'version' => $version
295
-		]);
296
-	}
297
-
298
-	/**
299
-	 * Returns the name of the table which holds the already applied versions
300
-	 *
301
-	 * @return string
302
-	 */
303
-	public function getMigrationsTableName() {
304
-		return $this->connection->getPrefix() . 'migrations';
305
-	}
306
-
307
-	/**
308
-	 * Returns the namespace of the version classes
309
-	 *
310
-	 * @return string
311
-	 */
312
-	public function getMigrationsNamespace() {
313
-		return $this->migrationsNamespace;
314
-	}
315
-
316
-	/**
317
-	 * Returns the directory which holds the versions
318
-	 *
319
-	 * @return string
320
-	 */
321
-	public function getMigrationsDirectory() {
322
-		return $this->migrationsPath;
323
-	}
324
-
325
-	/**
326
-	 * Return the explicit version for the aliases; current, next, prev, latest
327
-	 *
328
-	 * @param string $alias
329
-	 * @return mixed|null|string
330
-	 */
331
-	public function getMigration($alias) {
332
-		switch($alias) {
333
-			case 'current':
334
-				return $this->getCurrentVersion();
335
-			case 'next':
336
-				return $this->getRelativeVersion($this->getCurrentVersion(), 1);
337
-			case 'prev':
338
-				return $this->getRelativeVersion($this->getCurrentVersion(), -1);
339
-			case 'latest':
340
-				$this->ensureMigrationsAreLoaded();
341
-
342
-				$migrations = $this->getAvailableVersions();
343
-				return @end($migrations);
344
-		}
345
-		return '0';
346
-	}
347
-
348
-	/**
349
-	 * @param string $version
350
-	 * @param int $delta
351
-	 * @return null|string
352
-	 */
353
-	private function getRelativeVersion($version, $delta) {
354
-		$this->ensureMigrationsAreLoaded();
355
-
356
-		$versions = $this->getAvailableVersions();
357
-		array_unshift($versions, 0);
358
-		$offset = array_search($version, $versions, true);
359
-		if ($offset === false || !isset($versions[$offset + $delta])) {
360
-			// Unknown version or delta out of bounds.
361
-			return null;
362
-		}
363
-
364
-		return (string) $versions[$offset + $delta];
365
-	}
366
-
367
-	/**
368
-	 * @return string
369
-	 */
370
-	private function getCurrentVersion() {
371
-		$m = $this->getMigratedVersions();
372
-		if (count($m) === 0) {
373
-			return '0';
374
-		}
375
-		$migrations = array_values($m);
376
-		return @end($migrations);
377
-	}
378
-
379
-	/**
380
-	 * @param string $version
381
-	 * @return string
382
-	 * @throws \InvalidArgumentException
383
-	 */
384
-	private function getClass($version) {
385
-		$this->ensureMigrationsAreLoaded();
386
-
387
-		if (isset($this->migrations[$version])) {
388
-			return $this->migrations[$version];
389
-		}
390
-
391
-		throw new \InvalidArgumentException("Version $version is unknown.");
392
-	}
393
-
394
-	/**
395
-	 * Allows to set an IOutput implementation which is used for logging progress and messages
396
-	 *
397
-	 * @param IOutput $output
398
-	 */
399
-	public function setOutput(IOutput $output) {
400
-		$this->output = $output;
401
-	}
402
-
403
-	/**
404
-	 * Applies all not yet applied versions up to $to
405
-	 *
406
-	 * @param string $to
407
-	 * @param bool $schemaOnly
408
-	 * @throws \InvalidArgumentException
409
-	 */
410
-	public function migrate($to = 'latest', $schemaOnly = false) {
411
-		// read known migrations
412
-		$toBeExecuted = $this->getMigrationsToExecute($to);
413
-		foreach ($toBeExecuted as $version) {
414
-			$this->executeStep($version, $schemaOnly);
415
-		}
416
-	}
417
-
418
-	/**
419
-	 * Get the human readable descriptions for the migration steps to run
420
-	 *
421
-	 * @param string $to
422
-	 * @return string[] [$name => $description]
423
-	 */
424
-	public function describeMigrationStep($to = 'latest') {
425
-		$toBeExecuted = $this->getMigrationsToExecute($to);
426
-		$description = [];
427
-		foreach ($toBeExecuted as $version) {
428
-			$migration = $this->createInstance($version);
429
-			if ($migration->name()) {
430
-				$description[$migration->name()] = $migration->description();
431
-			}
432
-		}
433
-		return $description;
434
-	}
435
-
436
-	/**
437
-	 * @param string $version
438
-	 * @return IMigrationStep
439
-	 * @throws \InvalidArgumentException
440
-	 */
441
-	protected function createInstance($version) {
442
-		$class = $this->getClass($version);
443
-		try {
444
-			$s = \OC::$server->query($class);
445
-
446
-			if (!$s instanceof IMigrationStep) {
447
-				throw new \InvalidArgumentException('Not a valid migration');
448
-			}
449
-		} catch (QueryException $e) {
450
-			if (class_exists($class)) {
451
-				$s = new $class();
452
-			} else {
453
-				throw new \InvalidArgumentException("Migration step '$class' is unknown");
454
-			}
455
-		}
456
-
457
-		return $s;
458
-	}
459
-
460
-	/**
461
-	 * Executes one explicit version
462
-	 *
463
-	 * @param string $version
464
-	 * @param bool $schemaOnly
465
-	 * @throws \InvalidArgumentException
466
-	 */
467
-	public function executeStep($version, $schemaOnly = false) {
468
-		$instance = $this->createInstance($version);
469
-
470
-		if (!$schemaOnly) {
471
-			$instance->preSchemaChange($this->output, function () {
472
-				return new SchemaWrapper($this->connection);
473
-			}, ['tablePrefix' => $this->connection->getPrefix()]);
474
-		}
475
-
476
-		$toSchema = $instance->changeSchema($this->output, function () {
477
-			return new SchemaWrapper($this->connection);
478
-		}, ['tablePrefix' => $this->connection->getPrefix()]);
479
-
480
-		if ($toSchema instanceof SchemaWrapper) {
481
-			$targetSchema = $toSchema->getWrappedSchema();
482
-			if ($this->checkOracle) {
483
-				$sourceSchema = $this->connection->createSchema();
484
-				$this->ensureOracleIdentifierLengthLimit($sourceSchema, $targetSchema, strlen($this->connection->getPrefix()));
485
-			}
486
-			$this->connection->migrateToSchema($targetSchema);
487
-			$toSchema->performDropTableCalls();
488
-		}
489
-
490
-		if (!$schemaOnly) {
491
-			$instance->postSchemaChange($this->output, function () {
492
-				return new SchemaWrapper($this->connection);
493
-			}, ['tablePrefix' => $this->connection->getPrefix()]);
494
-		}
495
-
496
-		$this->markAsExecuted($version);
497
-	}
498
-
499
-	public function ensureOracleIdentifierLengthLimit(Schema $sourceSchema, Schema $targetSchema, int $prefixLength) {
500
-		$sequences = $targetSchema->getSequences();
501
-
502
-		foreach ($targetSchema->getTables() as $table) {
503
-			try {
504
-				$sourceTable = $sourceSchema->getTable($table->getName());
505
-			} catch (SchemaException $e) {
506
-				if (\strlen($table->getName()) - $prefixLength > 27) {
507
-					throw new \InvalidArgumentException('Table name "'  . $table->getName() . '" is too long.');
508
-				}
509
-				$sourceTable = null;
510
-			}
511
-
512
-			foreach ($table->getColumns() as $thing) {
513
-				if ((!$sourceTable instanceof Table || !$sourceTable->hasColumn($thing->getName())) && \strlen($thing->getName()) > 30) {
514
-					throw new \InvalidArgumentException('Column name "'  . $table->getName() . '"."' . $thing->getName() . '" is too long.');
515
-				}
516
-			}
517
-
518
-			foreach ($table->getIndexes() as $thing) {
519
-				if ((!$sourceTable instanceof Table || !$sourceTable->hasIndex($thing->getName())) && \strlen($thing->getName()) > 30) {
520
-					throw new \InvalidArgumentException('Index name "'  . $table->getName() . '"."' . $thing->getName() . '" is too long.');
521
-				}
522
-			}
523
-
524
-			foreach ($table->getForeignKeys() as $thing) {
525
-				if ((!$sourceTable instanceof Table || !$sourceTable->hasForeignKey($thing->getName())) && \strlen($thing->getName()) > 30) {
526
-					throw new \InvalidArgumentException('Foreign key name "'  . $table->getName() . '"."' . $thing->getName() . '" is too long.');
527
-				}
528
-			}
529
-
530
-			$primaryKey = $table->getPrimaryKey();
531
-			if ($primaryKey instanceof Index && (!$sourceTable instanceof Table || !$sourceTable->hasPrimaryKey())) {
532
-				$indexName = strtolower($primaryKey->getName());
533
-				$isUsingDefaultName = $indexName === 'primary';
534
-
535
-				if ($this->connection->getDatabasePlatform() instanceof PostgreSqlPlatform) {
536
-					$defaultName = $table->getName() . '_pkey';
537
-					$isUsingDefaultName = strtolower($defaultName) === $indexName;
538
-
539
-					if ($isUsingDefaultName) {
540
-						$sequenceName = $table->getName() . '_' . implode('_', $primaryKey->getColumns()) . '_seq';
541
-						$sequences = array_filter($sequences, function (Sequence $sequence) use ($sequenceName) {
542
-							return $sequence->getName() !== $sequenceName;
543
-						});
544
-					}
545
-				} else if ($this->connection->getDatabasePlatform() instanceof OraclePlatform) {
546
-					$defaultName = $table->getName() . '_seq';
547
-					$isUsingDefaultName = strtolower($defaultName) === $indexName;
548
-				}
549
-
550
-				if (!$isUsingDefaultName && \strlen($indexName) > 30) {
551
-					throw new \InvalidArgumentException('Primary index name  on "'  . $table->getName() . '" is too long.');
552
-				}
553
-				if ($isUsingDefaultName && \strlen($table->getName()) - $prefixLength >= 23) {
554
-					throw new \InvalidArgumentException('Primary index name  on "'  . $table->getName() . '" is too long.');
555
-				}
556
-			}
557
-		}
558
-
559
-		foreach ($sequences as $sequence) {
560
-			if (!$sourceSchema->hasSequence($sequence->getName()) && \strlen($sequence->getName()) > 30) {
561
-				throw new \InvalidArgumentException('Sequence name "'  . $sequence->getName() . '" is too long.');
562
-			}
563
-		}
564
-	}
565
-
566
-	private function ensureMigrationsAreLoaded() {
567
-		if (empty($this->migrations)) {
568
-			$this->migrations = $this->findMigrations();
569
-		}
570
-	}
48
+    /** @var boolean */
49
+    private $migrationTableCreated;
50
+    /** @var array */
51
+    private $migrations;
52
+    /** @var IOutput */
53
+    private $output;
54
+    /** @var Connection */
55
+    private $connection;
56
+    /** @var string */
57
+    private $appName;
58
+    /** @var bool */
59
+    private $checkOracle;
60
+
61
+    /**
62
+     * MigrationService constructor.
63
+     *
64
+     * @param $appName
65
+     * @param IDBConnection $connection
66
+     * @param AppLocator $appLocator
67
+     * @param IOutput|null $output
68
+     * @throws \Exception
69
+     */
70
+    public function __construct($appName, IDBConnection $connection, IOutput $output = null, AppLocator $appLocator = null) {
71
+        $this->appName = $appName;
72
+        $this->connection = $connection;
73
+        $this->output = $output;
74
+        if (null === $this->output) {
75
+            $this->output = new SimpleOutput(\OC::$server->getLogger(), $appName);
76
+        }
77
+
78
+        if ($appName === 'core') {
79
+            $this->migrationsPath = \OC::$SERVERROOT . '/core/Migrations';
80
+            $this->migrationsNamespace = 'OC\\Core\\Migrations';
81
+            $this->checkOracle = true;
82
+        } else {
83
+            if (null === $appLocator) {
84
+                $appLocator = new AppLocator();
85
+            }
86
+            $appPath = $appLocator->getAppPath($appName);
87
+            $namespace = App::buildAppNamespace($appName);
88
+            $this->migrationsPath = "$appPath/lib/Migration";
89
+            $this->migrationsNamespace = $namespace . '\\Migration';
90
+
91
+            $infoParser = new InfoParser();
92
+            $info = $infoParser->parse($appPath . '/appinfo/info.xml');
93
+            if (!isset($info['dependencies']['database'])) {
94
+                $this->checkOracle = true;
95
+            } else {
96
+                $this->checkOracle = false;
97
+                foreach ($info['dependencies']['database'] as $database) {
98
+                    if (\is_string($database) && $database === 'oci') {
99
+                        $this->checkOracle = true;
100
+                    } else if (\is_array($database) && isset($database['@value']) && $database['@value'] === 'oci') {
101
+                        $this->checkOracle = true;
102
+                    }
103
+                }
104
+            }
105
+        }
106
+    }
107
+
108
+    /**
109
+     * Returns the name of the app for which this migration is executed
110
+     *
111
+     * @return string
112
+     */
113
+    public function getApp() {
114
+        return $this->appName;
115
+    }
116
+
117
+    /**
118
+     * @return bool
119
+     * @codeCoverageIgnore - this will implicitly tested on installation
120
+     */
121
+    private function createMigrationTable() {
122
+        if ($this->migrationTableCreated) {
123
+            return false;
124
+        }
125
+
126
+        $schema = new SchemaWrapper($this->connection);
127
+
128
+        /**
129
+         * We drop the table when it has different columns or the definition does not
130
+         * match. E.g. ownCloud uses a length of 177 for app and 14 for version.
131
+         */
132
+        try {
133
+            $table = $schema->getTable('migrations');
134
+            $columns = $table->getColumns();
135
+
136
+            if (count($columns) === 2) {
137
+                try {
138
+                    $column = $table->getColumn('app');
139
+                    $schemaMismatch = $column->getLength() !== 255;
140
+
141
+                    if (!$schemaMismatch) {
142
+                        $column = $table->getColumn('version');
143
+                        $schemaMismatch = $column->getLength() !== 255;
144
+                    }
145
+                } catch (SchemaException $e) {
146
+                    // One of the columns is missing
147
+                    $schemaMismatch = true;
148
+                }
149
+
150
+                if (!$schemaMismatch) {
151
+                    // Table exists and schema matches: return back!
152
+                    $this->migrationTableCreated = true;
153
+                    return false;
154
+                }
155
+            }
156
+
157
+            // Drop the table, when it didn't match our expectations.
158
+            $this->connection->dropTable('migrations');
159
+
160
+            // Recreate the schema after the table was dropped.
161
+            $schema = new SchemaWrapper($this->connection);
162
+
163
+        } catch (SchemaException $e) {
164
+            // Table not found, no need to panic, we will create it.
165
+        }
166
+
167
+        $table = $schema->createTable('migrations');
168
+        $table->addColumn('app', Type::STRING, ['length' => 255]);
169
+        $table->addColumn('version', Type::STRING, ['length' => 255]);
170
+        $table->setPrimaryKey(['app', 'version']);
171
+
172
+        $this->connection->migrateToSchema($schema->getWrappedSchema());
173
+
174
+        $this->migrationTableCreated = true;
175
+
176
+        return true;
177
+    }
178
+
179
+    /**
180
+     * Returns all versions which have already been applied
181
+     *
182
+     * @return string[]
183
+     * @codeCoverageIgnore - no need to test this
184
+     */
185
+    public function getMigratedVersions() {
186
+        $this->createMigrationTable();
187
+        $qb = $this->connection->getQueryBuilder();
188
+
189
+        $qb->select('version')
190
+            ->from('migrations')
191
+            ->where($qb->expr()->eq('app', $qb->createNamedParameter($this->getApp())))
192
+            ->orderBy('version');
193
+
194
+        $result = $qb->execute();
195
+        $rows = $result->fetchAll(\PDO::FETCH_COLUMN);
196
+        $result->closeCursor();
197
+
198
+        return $rows;
199
+    }
200
+
201
+    /**
202
+     * Returns all versions which are available in the migration folder
203
+     *
204
+     * @return array
205
+     */
206
+    public function getAvailableVersions() {
207
+        $this->ensureMigrationsAreLoaded();
208
+        return array_map('strval', array_keys($this->migrations));
209
+    }
210
+
211
+    protected function findMigrations() {
212
+        $directory = realpath($this->migrationsPath);
213
+        if ($directory === false || !file_exists($directory) || !is_dir($directory)) {
214
+            return [];
215
+        }
216
+
217
+        $iterator = new \RegexIterator(
218
+            new \RecursiveIteratorIterator(
219
+                new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS),
220
+                \RecursiveIteratorIterator::LEAVES_ONLY
221
+            ),
222
+            '#^.+\\/Version[^\\/]{1,255}\\.php$#i',
223
+            \RegexIterator::GET_MATCH);
224
+
225
+        $files = array_keys(iterator_to_array($iterator));
226
+        uasort($files, function ($a, $b) {
227
+            preg_match('/^Version(\d+)Date(\d+)\\.php$/', basename($a), $matchA);
228
+            preg_match('/^Version(\d+)Date(\d+)\\.php$/', basename($b), $matchB);
229
+            if (!empty($matchA) && !empty($matchB)) {
230
+                if ($matchA[1] !== $matchB[1]) {
231
+                    return ($matchA[1] < $matchB[1]) ? -1 : 1;
232
+                }
233
+                return ($matchA[2] < $matchB[2]) ? -1 : 1;
234
+            }
235
+            return (basename($a) < basename($b)) ? -1 : 1;
236
+        });
237
+
238
+        $migrations = [];
239
+
240
+        foreach ($files as $file) {
241
+            $className = basename($file, '.php');
242
+            $version = (string) substr($className, 7);
243
+            if ($version === '0') {
244
+                throw new \InvalidArgumentException(
245
+                    "Cannot load a migrations with the name '$version' because it is a reserved number"
246
+                );
247
+            }
248
+            $migrations[$version] = sprintf('%s\\%s', $this->migrationsNamespace, $className);
249
+        }
250
+
251
+        return $migrations;
252
+    }
253
+
254
+    /**
255
+     * @param string $to
256
+     * @return string[]
257
+     */
258
+    private function getMigrationsToExecute($to) {
259
+        $knownMigrations = $this->getMigratedVersions();
260
+        $availableMigrations = $this->getAvailableVersions();
261
+
262
+        $toBeExecuted = [];
263
+        foreach ($availableMigrations as $v) {
264
+            if ($to !== 'latest' && $v > $to) {
265
+                continue;
266
+            }
267
+            if ($this->shallBeExecuted($v, $knownMigrations)) {
268
+                $toBeExecuted[] = $v;
269
+            }
270
+        }
271
+
272
+        return $toBeExecuted;
273
+    }
274
+
275
+    /**
276
+     * @param string $m
277
+     * @param string[] $knownMigrations
278
+     * @return bool
279
+     */
280
+    private function shallBeExecuted($m, $knownMigrations) {
281
+        if (in_array($m, $knownMigrations)) {
282
+            return false;
283
+        }
284
+
285
+        return true;
286
+    }
287
+
288
+    /**
289
+     * @param string $version
290
+     */
291
+    private function markAsExecuted($version) {
292
+        $this->connection->insertIfNotExist('*PREFIX*migrations', [
293
+            'app' => $this->appName,
294
+            'version' => $version
295
+        ]);
296
+    }
297
+
298
+    /**
299
+     * Returns the name of the table which holds the already applied versions
300
+     *
301
+     * @return string
302
+     */
303
+    public function getMigrationsTableName() {
304
+        return $this->connection->getPrefix() . 'migrations';
305
+    }
306
+
307
+    /**
308
+     * Returns the namespace of the version classes
309
+     *
310
+     * @return string
311
+     */
312
+    public function getMigrationsNamespace() {
313
+        return $this->migrationsNamespace;
314
+    }
315
+
316
+    /**
317
+     * Returns the directory which holds the versions
318
+     *
319
+     * @return string
320
+     */
321
+    public function getMigrationsDirectory() {
322
+        return $this->migrationsPath;
323
+    }
324
+
325
+    /**
326
+     * Return the explicit version for the aliases; current, next, prev, latest
327
+     *
328
+     * @param string $alias
329
+     * @return mixed|null|string
330
+     */
331
+    public function getMigration($alias) {
332
+        switch($alias) {
333
+            case 'current':
334
+                return $this->getCurrentVersion();
335
+            case 'next':
336
+                return $this->getRelativeVersion($this->getCurrentVersion(), 1);
337
+            case 'prev':
338
+                return $this->getRelativeVersion($this->getCurrentVersion(), -1);
339
+            case 'latest':
340
+                $this->ensureMigrationsAreLoaded();
341
+
342
+                $migrations = $this->getAvailableVersions();
343
+                return @end($migrations);
344
+        }
345
+        return '0';
346
+    }
347
+
348
+    /**
349
+     * @param string $version
350
+     * @param int $delta
351
+     * @return null|string
352
+     */
353
+    private function getRelativeVersion($version, $delta) {
354
+        $this->ensureMigrationsAreLoaded();
355
+
356
+        $versions = $this->getAvailableVersions();
357
+        array_unshift($versions, 0);
358
+        $offset = array_search($version, $versions, true);
359
+        if ($offset === false || !isset($versions[$offset + $delta])) {
360
+            // Unknown version or delta out of bounds.
361
+            return null;
362
+        }
363
+
364
+        return (string) $versions[$offset + $delta];
365
+    }
366
+
367
+    /**
368
+     * @return string
369
+     */
370
+    private function getCurrentVersion() {
371
+        $m = $this->getMigratedVersions();
372
+        if (count($m) === 0) {
373
+            return '0';
374
+        }
375
+        $migrations = array_values($m);
376
+        return @end($migrations);
377
+    }
378
+
379
+    /**
380
+     * @param string $version
381
+     * @return string
382
+     * @throws \InvalidArgumentException
383
+     */
384
+    private function getClass($version) {
385
+        $this->ensureMigrationsAreLoaded();
386
+
387
+        if (isset($this->migrations[$version])) {
388
+            return $this->migrations[$version];
389
+        }
390
+
391
+        throw new \InvalidArgumentException("Version $version is unknown.");
392
+    }
393
+
394
+    /**
395
+     * Allows to set an IOutput implementation which is used for logging progress and messages
396
+     *
397
+     * @param IOutput $output
398
+     */
399
+    public function setOutput(IOutput $output) {
400
+        $this->output = $output;
401
+    }
402
+
403
+    /**
404
+     * Applies all not yet applied versions up to $to
405
+     *
406
+     * @param string $to
407
+     * @param bool $schemaOnly
408
+     * @throws \InvalidArgumentException
409
+     */
410
+    public function migrate($to = 'latest', $schemaOnly = false) {
411
+        // read known migrations
412
+        $toBeExecuted = $this->getMigrationsToExecute($to);
413
+        foreach ($toBeExecuted as $version) {
414
+            $this->executeStep($version, $schemaOnly);
415
+        }
416
+    }
417
+
418
+    /**
419
+     * Get the human readable descriptions for the migration steps to run
420
+     *
421
+     * @param string $to
422
+     * @return string[] [$name => $description]
423
+     */
424
+    public function describeMigrationStep($to = 'latest') {
425
+        $toBeExecuted = $this->getMigrationsToExecute($to);
426
+        $description = [];
427
+        foreach ($toBeExecuted as $version) {
428
+            $migration = $this->createInstance($version);
429
+            if ($migration->name()) {
430
+                $description[$migration->name()] = $migration->description();
431
+            }
432
+        }
433
+        return $description;
434
+    }
435
+
436
+    /**
437
+     * @param string $version
438
+     * @return IMigrationStep
439
+     * @throws \InvalidArgumentException
440
+     */
441
+    protected function createInstance($version) {
442
+        $class = $this->getClass($version);
443
+        try {
444
+            $s = \OC::$server->query($class);
445
+
446
+            if (!$s instanceof IMigrationStep) {
447
+                throw new \InvalidArgumentException('Not a valid migration');
448
+            }
449
+        } catch (QueryException $e) {
450
+            if (class_exists($class)) {
451
+                $s = new $class();
452
+            } else {
453
+                throw new \InvalidArgumentException("Migration step '$class' is unknown");
454
+            }
455
+        }
456
+
457
+        return $s;
458
+    }
459
+
460
+    /**
461
+     * Executes one explicit version
462
+     *
463
+     * @param string $version
464
+     * @param bool $schemaOnly
465
+     * @throws \InvalidArgumentException
466
+     */
467
+    public function executeStep($version, $schemaOnly = false) {
468
+        $instance = $this->createInstance($version);
469
+
470
+        if (!$schemaOnly) {
471
+            $instance->preSchemaChange($this->output, function () {
472
+                return new SchemaWrapper($this->connection);
473
+            }, ['tablePrefix' => $this->connection->getPrefix()]);
474
+        }
475
+
476
+        $toSchema = $instance->changeSchema($this->output, function () {
477
+            return new SchemaWrapper($this->connection);
478
+        }, ['tablePrefix' => $this->connection->getPrefix()]);
479
+
480
+        if ($toSchema instanceof SchemaWrapper) {
481
+            $targetSchema = $toSchema->getWrappedSchema();
482
+            if ($this->checkOracle) {
483
+                $sourceSchema = $this->connection->createSchema();
484
+                $this->ensureOracleIdentifierLengthLimit($sourceSchema, $targetSchema, strlen($this->connection->getPrefix()));
485
+            }
486
+            $this->connection->migrateToSchema($targetSchema);
487
+            $toSchema->performDropTableCalls();
488
+        }
489
+
490
+        if (!$schemaOnly) {
491
+            $instance->postSchemaChange($this->output, function () {
492
+                return new SchemaWrapper($this->connection);
493
+            }, ['tablePrefix' => $this->connection->getPrefix()]);
494
+        }
495
+
496
+        $this->markAsExecuted($version);
497
+    }
498
+
499
+    public function ensureOracleIdentifierLengthLimit(Schema $sourceSchema, Schema $targetSchema, int $prefixLength) {
500
+        $sequences = $targetSchema->getSequences();
501
+
502
+        foreach ($targetSchema->getTables() as $table) {
503
+            try {
504
+                $sourceTable = $sourceSchema->getTable($table->getName());
505
+            } catch (SchemaException $e) {
506
+                if (\strlen($table->getName()) - $prefixLength > 27) {
507
+                    throw new \InvalidArgumentException('Table name "'  . $table->getName() . '" is too long.');
508
+                }
509
+                $sourceTable = null;
510
+            }
511
+
512
+            foreach ($table->getColumns() as $thing) {
513
+                if ((!$sourceTable instanceof Table || !$sourceTable->hasColumn($thing->getName())) && \strlen($thing->getName()) > 30) {
514
+                    throw new \InvalidArgumentException('Column name "'  . $table->getName() . '"."' . $thing->getName() . '" is too long.');
515
+                }
516
+            }
517
+
518
+            foreach ($table->getIndexes() as $thing) {
519
+                if ((!$sourceTable instanceof Table || !$sourceTable->hasIndex($thing->getName())) && \strlen($thing->getName()) > 30) {
520
+                    throw new \InvalidArgumentException('Index name "'  . $table->getName() . '"."' . $thing->getName() . '" is too long.');
521
+                }
522
+            }
523
+
524
+            foreach ($table->getForeignKeys() as $thing) {
525
+                if ((!$sourceTable instanceof Table || !$sourceTable->hasForeignKey($thing->getName())) && \strlen($thing->getName()) > 30) {
526
+                    throw new \InvalidArgumentException('Foreign key name "'  . $table->getName() . '"."' . $thing->getName() . '" is too long.');
527
+                }
528
+            }
529
+
530
+            $primaryKey = $table->getPrimaryKey();
531
+            if ($primaryKey instanceof Index && (!$sourceTable instanceof Table || !$sourceTable->hasPrimaryKey())) {
532
+                $indexName = strtolower($primaryKey->getName());
533
+                $isUsingDefaultName = $indexName === 'primary';
534
+
535
+                if ($this->connection->getDatabasePlatform() instanceof PostgreSqlPlatform) {
536
+                    $defaultName = $table->getName() . '_pkey';
537
+                    $isUsingDefaultName = strtolower($defaultName) === $indexName;
538
+
539
+                    if ($isUsingDefaultName) {
540
+                        $sequenceName = $table->getName() . '_' . implode('_', $primaryKey->getColumns()) . '_seq';
541
+                        $sequences = array_filter($sequences, function (Sequence $sequence) use ($sequenceName) {
542
+                            return $sequence->getName() !== $sequenceName;
543
+                        });
544
+                    }
545
+                } else if ($this->connection->getDatabasePlatform() instanceof OraclePlatform) {
546
+                    $defaultName = $table->getName() . '_seq';
547
+                    $isUsingDefaultName = strtolower($defaultName) === $indexName;
548
+                }
549
+
550
+                if (!$isUsingDefaultName && \strlen($indexName) > 30) {
551
+                    throw new \InvalidArgumentException('Primary index name  on "'  . $table->getName() . '" is too long.');
552
+                }
553
+                if ($isUsingDefaultName && \strlen($table->getName()) - $prefixLength >= 23) {
554
+                    throw new \InvalidArgumentException('Primary index name  on "'  . $table->getName() . '" is too long.');
555
+                }
556
+            }
557
+        }
558
+
559
+        foreach ($sequences as $sequence) {
560
+            if (!$sourceSchema->hasSequence($sequence->getName()) && \strlen($sequence->getName()) > 30) {
561
+                throw new \InvalidArgumentException('Sequence name "'  . $sequence->getName() . '" is too long.');
562
+            }
563
+        }
564
+    }
565
+
566
+    private function ensureMigrationsAreLoaded() {
567
+        if (empty($this->migrations)) {
568
+            $this->migrations = $this->findMigrations();
569
+        }
570
+    }
571 571
 }
Please login to merge, or discard this patch.
Spacing   +20 added lines, -20 removed lines patch added patch discarded remove patch
@@ -76,7 +76,7 @@  discard block
 block discarded – undo
76 76
 		}
77 77
 
78 78
 		if ($appName === 'core') {
79
-			$this->migrationsPath = \OC::$SERVERROOT . '/core/Migrations';
79
+			$this->migrationsPath = \OC::$SERVERROOT.'/core/Migrations';
80 80
 			$this->migrationsNamespace = 'OC\\Core\\Migrations';
81 81
 			$this->checkOracle = true;
82 82
 		} else {
@@ -86,10 +86,10 @@  discard block
 block discarded – undo
86 86
 			$appPath = $appLocator->getAppPath($appName);
87 87
 			$namespace = App::buildAppNamespace($appName);
88 88
 			$this->migrationsPath = "$appPath/lib/Migration";
89
-			$this->migrationsNamespace = $namespace . '\\Migration';
89
+			$this->migrationsNamespace = $namespace.'\\Migration';
90 90
 
91 91
 			$infoParser = new InfoParser();
92
-			$info = $infoParser->parse($appPath . '/appinfo/info.xml');
92
+			$info = $infoParser->parse($appPath.'/appinfo/info.xml');
93 93
 			if (!isset($info['dependencies']['database'])) {
94 94
 				$this->checkOracle = true;
95 95
 			} else {
@@ -223,7 +223,7 @@  discard block
 block discarded – undo
223 223
 			\RegexIterator::GET_MATCH);
224 224
 
225 225
 		$files = array_keys(iterator_to_array($iterator));
226
-		uasort($files, function ($a, $b) {
226
+		uasort($files, function($a, $b) {
227 227
 			preg_match('/^Version(\d+)Date(\d+)\\.php$/', basename($a), $matchA);
228 228
 			preg_match('/^Version(\d+)Date(\d+)\\.php$/', basename($b), $matchB);
229 229
 			if (!empty($matchA) && !empty($matchB)) {
@@ -301,7 +301,7 @@  discard block
 block discarded – undo
301 301
 	 * @return string
302 302
 	 */
303 303
 	public function getMigrationsTableName() {
304
-		return $this->connection->getPrefix() . 'migrations';
304
+		return $this->connection->getPrefix().'migrations';
305 305
 	}
306 306
 
307 307
 	/**
@@ -329,7 +329,7 @@  discard block
 block discarded – undo
329 329
 	 * @return mixed|null|string
330 330
 	 */
331 331
 	public function getMigration($alias) {
332
-		switch($alias) {
332
+		switch ($alias) {
333 333
 			case 'current':
334 334
 				return $this->getCurrentVersion();
335 335
 			case 'next':
@@ -468,12 +468,12 @@  discard block
 block discarded – undo
468 468
 		$instance = $this->createInstance($version);
469 469
 
470 470
 		if (!$schemaOnly) {
471
-			$instance->preSchemaChange($this->output, function () {
471
+			$instance->preSchemaChange($this->output, function() {
472 472
 				return new SchemaWrapper($this->connection);
473 473
 			}, ['tablePrefix' => $this->connection->getPrefix()]);
474 474
 		}
475 475
 
476
-		$toSchema = $instance->changeSchema($this->output, function () {
476
+		$toSchema = $instance->changeSchema($this->output, function() {
477 477
 			return new SchemaWrapper($this->connection);
478 478
 		}, ['tablePrefix' => $this->connection->getPrefix()]);
479 479
 
@@ -488,7 +488,7 @@  discard block
 block discarded – undo
488 488
 		}
489 489
 
490 490
 		if (!$schemaOnly) {
491
-			$instance->postSchemaChange($this->output, function () {
491
+			$instance->postSchemaChange($this->output, function() {
492 492
 				return new SchemaWrapper($this->connection);
493 493
 			}, ['tablePrefix' => $this->connection->getPrefix()]);
494 494
 		}
@@ -504,26 +504,26 @@  discard block
 block discarded – undo
504 504
 				$sourceTable = $sourceSchema->getTable($table->getName());
505 505
 			} catch (SchemaException $e) {
506 506
 				if (\strlen($table->getName()) - $prefixLength > 27) {
507
-					throw new \InvalidArgumentException('Table name "'  . $table->getName() . '" is too long.');
507
+					throw new \InvalidArgumentException('Table name "'.$table->getName().'" is too long.');
508 508
 				}
509 509
 				$sourceTable = null;
510 510
 			}
511 511
 
512 512
 			foreach ($table->getColumns() as $thing) {
513 513
 				if ((!$sourceTable instanceof Table || !$sourceTable->hasColumn($thing->getName())) && \strlen($thing->getName()) > 30) {
514
-					throw new \InvalidArgumentException('Column name "'  . $table->getName() . '"."' . $thing->getName() . '" is too long.');
514
+					throw new \InvalidArgumentException('Column name "'.$table->getName().'"."'.$thing->getName().'" is too long.');
515 515
 				}
516 516
 			}
517 517
 
518 518
 			foreach ($table->getIndexes() as $thing) {
519 519
 				if ((!$sourceTable instanceof Table || !$sourceTable->hasIndex($thing->getName())) && \strlen($thing->getName()) > 30) {
520
-					throw new \InvalidArgumentException('Index name "'  . $table->getName() . '"."' . $thing->getName() . '" is too long.');
520
+					throw new \InvalidArgumentException('Index name "'.$table->getName().'"."'.$thing->getName().'" is too long.');
521 521
 				}
522 522
 			}
523 523
 
524 524
 			foreach ($table->getForeignKeys() as $thing) {
525 525
 				if ((!$sourceTable instanceof Table || !$sourceTable->hasForeignKey($thing->getName())) && \strlen($thing->getName()) > 30) {
526
-					throw new \InvalidArgumentException('Foreign key name "'  . $table->getName() . '"."' . $thing->getName() . '" is too long.');
526
+					throw new \InvalidArgumentException('Foreign key name "'.$table->getName().'"."'.$thing->getName().'" is too long.');
527 527
 				}
528 528
 			}
529 529
 
@@ -533,32 +533,32 @@  discard block
 block discarded – undo
533 533
 				$isUsingDefaultName = $indexName === 'primary';
534 534
 
535 535
 				if ($this->connection->getDatabasePlatform() instanceof PostgreSqlPlatform) {
536
-					$defaultName = $table->getName() . '_pkey';
536
+					$defaultName = $table->getName().'_pkey';
537 537
 					$isUsingDefaultName = strtolower($defaultName) === $indexName;
538 538
 
539 539
 					if ($isUsingDefaultName) {
540
-						$sequenceName = $table->getName() . '_' . implode('_', $primaryKey->getColumns()) . '_seq';
541
-						$sequences = array_filter($sequences, function (Sequence $sequence) use ($sequenceName) {
540
+						$sequenceName = $table->getName().'_'.implode('_', $primaryKey->getColumns()).'_seq';
541
+						$sequences = array_filter($sequences, function(Sequence $sequence) use ($sequenceName) {
542 542
 							return $sequence->getName() !== $sequenceName;
543 543
 						});
544 544
 					}
545 545
 				} else if ($this->connection->getDatabasePlatform() instanceof OraclePlatform) {
546
-					$defaultName = $table->getName() . '_seq';
546
+					$defaultName = $table->getName().'_seq';
547 547
 					$isUsingDefaultName = strtolower($defaultName) === $indexName;
548 548
 				}
549 549
 
550 550
 				if (!$isUsingDefaultName && \strlen($indexName) > 30) {
551
-					throw new \InvalidArgumentException('Primary index name  on "'  . $table->getName() . '" is too long.');
551
+					throw new \InvalidArgumentException('Primary index name  on "'.$table->getName().'" is too long.');
552 552
 				}
553 553
 				if ($isUsingDefaultName && \strlen($table->getName()) - $prefixLength >= 23) {
554
-					throw new \InvalidArgumentException('Primary index name  on "'  . $table->getName() . '" is too long.');
554
+					throw new \InvalidArgumentException('Primary index name  on "'.$table->getName().'" is too long.');
555 555
 				}
556 556
 			}
557 557
 		}
558 558
 
559 559
 		foreach ($sequences as $sequence) {
560 560
 			if (!$sourceSchema->hasSequence($sequence->getName()) && \strlen($sequence->getName()) > 30) {
561
-				throw new \InvalidArgumentException('Sequence name "'  . $sequence->getName() . '" is too long.');
561
+				throw new \InvalidArgumentException('Sequence name "'.$sequence->getName().'" is too long.');
562 562
 			}
563 563
 		}
564 564
 	}
Please login to merge, or discard this patch.
lib/private/DB/OracleConnection.php 2 patches
Indentation   +71 added lines, -71 removed lines patch added patch discarded remove patch
@@ -28,80 +28,80 @@
 block discarded – undo
28 28
 namespace OC\DB;
29 29
 
30 30
 class OracleConnection extends Connection {
31
-	/**
32
-	 * Quote the keys of the array
33
-	 */
34
-	private function quoteKeys(array $data) {
35
-		$return = [];
36
-		$c = $this->getDatabasePlatform()->getIdentifierQuoteCharacter();
37
-		foreach($data as $key => $value) {
38
-			if ($key[0] !== $c) {
39
-				$return[$this->quoteIdentifier($key)] = $value;
40
-			} else {
41
-				$return[$key] = $value;
42
-			}
43
-		}
44
-		return $return;
45
-	}
31
+    /**
32
+     * Quote the keys of the array
33
+     */
34
+    private function quoteKeys(array $data) {
35
+        $return = [];
36
+        $c = $this->getDatabasePlatform()->getIdentifierQuoteCharacter();
37
+        foreach($data as $key => $value) {
38
+            if ($key[0] !== $c) {
39
+                $return[$this->quoteIdentifier($key)] = $value;
40
+            } else {
41
+                $return[$key] = $value;
42
+            }
43
+        }
44
+        return $return;
45
+    }
46 46
 
47
-	/**
48
-	 * {@inheritDoc}
49
-	 */
50
-	public function insert($tableName, array $data, array $types = []) {
51
-		if ($tableName[0] !== $this->getDatabasePlatform()->getIdentifierQuoteCharacter()) {
52
-			$tableName = $this->quoteIdentifier($tableName);
53
-		}
54
-		$data = $this->quoteKeys($data);
55
-		return parent::insert($tableName, $data, $types);
56
-	}
47
+    /**
48
+     * {@inheritDoc}
49
+     */
50
+    public function insert($tableName, array $data, array $types = []) {
51
+        if ($tableName[0] !== $this->getDatabasePlatform()->getIdentifierQuoteCharacter()) {
52
+            $tableName = $this->quoteIdentifier($tableName);
53
+        }
54
+        $data = $this->quoteKeys($data);
55
+        return parent::insert($tableName, $data, $types);
56
+    }
57 57
 
58
-	/**
59
-	 * {@inheritDoc}
60
-	 */
61
-	public function update($tableName, array $data, array $identifier, array $types = []) {
62
-		if ($tableName[0] !== $this->getDatabasePlatform()->getIdentifierQuoteCharacter()) {
63
-			$tableName = $this->quoteIdentifier($tableName);
64
-		}
65
-		$data = $this->quoteKeys($data);
66
-		$identifier = $this->quoteKeys($identifier);
67
-		return parent::update($tableName, $data, $identifier, $types);
68
-	}
58
+    /**
59
+     * {@inheritDoc}
60
+     */
61
+    public function update($tableName, array $data, array $identifier, array $types = []) {
62
+        if ($tableName[0] !== $this->getDatabasePlatform()->getIdentifierQuoteCharacter()) {
63
+            $tableName = $this->quoteIdentifier($tableName);
64
+        }
65
+        $data = $this->quoteKeys($data);
66
+        $identifier = $this->quoteKeys($identifier);
67
+        return parent::update($tableName, $data, $identifier, $types);
68
+    }
69 69
 
70
-	/**
71
-	 * {@inheritDoc}
72
-	 */
73
-	public function delete($tableExpression, array $identifier, array $types = []) {
74
-		if ($tableExpression[0] !== $this->getDatabasePlatform()->getIdentifierQuoteCharacter()) {
75
-			$tableExpression = $this->quoteIdentifier($tableExpression);
76
-		}
77
-		$identifier = $this->quoteKeys($identifier);
78
-		return parent::delete($tableExpression, $identifier);
79
-	}
70
+    /**
71
+     * {@inheritDoc}
72
+     */
73
+    public function delete($tableExpression, array $identifier, array $types = []) {
74
+        if ($tableExpression[0] !== $this->getDatabasePlatform()->getIdentifierQuoteCharacter()) {
75
+            $tableExpression = $this->quoteIdentifier($tableExpression);
76
+        }
77
+        $identifier = $this->quoteKeys($identifier);
78
+        return parent::delete($tableExpression, $identifier);
79
+    }
80 80
 
81
-	/**
82
-	 * Drop a table from the database if it exists
83
-	 *
84
-	 * @param string $table table name without the prefix
85
-	 */
86
-	public function dropTable($table) {
87
-		$table = $this->tablePrefix . trim($table);
88
-		$table = $this->quoteIdentifier($table);
89
-		$schema = $this->getSchemaManager();
90
-		if($schema->tablesExist([$table])) {
91
-			$schema->dropTable($table);
92
-		}
93
-	}
81
+    /**
82
+     * Drop a table from the database if it exists
83
+     *
84
+     * @param string $table table name without the prefix
85
+     */
86
+    public function dropTable($table) {
87
+        $table = $this->tablePrefix . trim($table);
88
+        $table = $this->quoteIdentifier($table);
89
+        $schema = $this->getSchemaManager();
90
+        if($schema->tablesExist([$table])) {
91
+            $schema->dropTable($table);
92
+        }
93
+    }
94 94
 
95
-	/**
96
-	 * Check if a table exists
97
-	 *
98
-	 * @param string $table table name without the prefix
99
-	 * @return bool
100
-	 */
101
-	public function tableExists($table) {
102
-		$table = $this->tablePrefix . trim($table);
103
-		$table = $this->quoteIdentifier($table);
104
-		$schema = $this->getSchemaManager();
105
-		return $schema->tablesExist([$table]);
106
-	}
95
+    /**
96
+     * Check if a table exists
97
+     *
98
+     * @param string $table table name without the prefix
99
+     * @return bool
100
+     */
101
+    public function tableExists($table) {
102
+        $table = $this->tablePrefix . trim($table);
103
+        $table = $this->quoteIdentifier($table);
104
+        $schema = $this->getSchemaManager();
105
+        return $schema->tablesExist([$table]);
106
+    }
107 107
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -34,7 +34,7 @@  discard block
 block discarded – undo
34 34
 	private function quoteKeys(array $data) {
35 35
 		$return = [];
36 36
 		$c = $this->getDatabasePlatform()->getIdentifierQuoteCharacter();
37
-		foreach($data as $key => $value) {
37
+		foreach ($data as $key => $value) {
38 38
 			if ($key[0] !== $c) {
39 39
 				$return[$this->quoteIdentifier($key)] = $value;
40 40
 			} else {
@@ -84,10 +84,10 @@  discard block
 block discarded – undo
84 84
 	 * @param string $table table name without the prefix
85 85
 	 */
86 86
 	public function dropTable($table) {
87
-		$table = $this->tablePrefix . trim($table);
87
+		$table = $this->tablePrefix.trim($table);
88 88
 		$table = $this->quoteIdentifier($table);
89 89
 		$schema = $this->getSchemaManager();
90
-		if($schema->tablesExist([$table])) {
90
+		if ($schema->tablesExist([$table])) {
91 91
 			$schema->dropTable($table);
92 92
 		}
93 93
 	}
@@ -99,7 +99,7 @@  discard block
 block discarded – undo
99 99
 	 * @return bool
100 100
 	 */
101 101
 	public function tableExists($table) {
102
-		$table = $this->tablePrefix . trim($table);
102
+		$table = $this->tablePrefix.trim($table);
103 103
 		$table = $this->quoteIdentifier($table);
104 104
 		$schema = $this->getSchemaManager();
105 105
 		return $schema->tablesExist([$table]);
Please login to merge, or discard this patch.
lib/private/DB/OracleMigrator.php 2 patches
Indentation   +189 added lines, -189 removed lines patch added patch discarded remove patch
@@ -39,194 +39,194 @@
 block discarded – undo
39 39
 
40 40
 class OracleMigrator extends Migrator {
41 41
 
42
-	/**
43
-	 * Quote a column's name but changing the name requires recreating
44
-	 * the column instance and copying over all properties.
45
-	 *
46
-	 * @param Column $column old column
47
-	 * @return Column new column instance with new name
48
-	 */
49
-	protected function quoteColumn(Column $column) {
50
-		$newColumn = new Column(
51
-			$this->connection->quoteIdentifier($column->getName()),
52
-			$column->getType()
53
-		);
54
-		$newColumn->setAutoincrement($column->getAutoincrement());
55
-		$newColumn->setColumnDefinition($column->getColumnDefinition());
56
-		$newColumn->setComment($column->getComment());
57
-		$newColumn->setDefault($column->getDefault());
58
-		$newColumn->setFixed($column->getFixed());
59
-		$newColumn->setLength($column->getLength());
60
-		$newColumn->setNotnull($column->getNotnull());
61
-		$newColumn->setPrecision($column->getPrecision());
62
-		$newColumn->setScale($column->getScale());
63
-		$newColumn->setUnsigned($column->getUnsigned());
64
-		$newColumn->setPlatformOptions($column->getPlatformOptions());
65
-		$newColumn->setCustomSchemaOptions($column->getPlatformOptions());
66
-		return $newColumn;
67
-	}
68
-
69
-	/**
70
-	 * Quote an index's name but changing the name requires recreating
71
-	 * the index instance and copying over all properties.
72
-	 *
73
-	 * @param Index $index old index
74
-	 * @return Index new index instance with new name
75
-	 */
76
-	protected function quoteIndex($index) {
77
-		return new Index(
78
-		//TODO migrate existing uppercase indexes, then $this->connection->quoteIdentifier($index->getName()),
79
-			$index->getName(),
80
-			array_map(function ($columnName) {
81
-				return $this->connection->quoteIdentifier($columnName);
82
-			}, $index->getColumns()),
83
-			$index->isUnique(),
84
-			$index->isPrimary(),
85
-			$index->getFlags(),
86
-			$index->getOptions()
87
-		);
88
-	}
89
-
90
-	/**
91
-	 * Quote an ForeignKeyConstraint's name but changing the name requires recreating
92
-	 * the ForeignKeyConstraint instance and copying over all properties.
93
-	 *
94
-	 * @param ForeignKeyConstraint $fkc old fkc
95
-	 * @return ForeignKeyConstraint new fkc instance with new name
96
-	 */
97
-	protected function quoteForeignKeyConstraint($fkc) {
98
-		return new ForeignKeyConstraint(
99
-			array_map(function ($columnName) {
100
-				return $this->connection->quoteIdentifier($columnName);
101
-			}, $fkc->getLocalColumns()),
102
-			$this->connection->quoteIdentifier($fkc->getForeignTableName()),
103
-			array_map(function ($columnName) {
104
-				return $this->connection->quoteIdentifier($columnName);
105
-			}, $fkc->getForeignColumns()),
106
-			$fkc->getName(),
107
-			$fkc->getOptions()
108
-		);
109
-	}
110
-
111
-	/**
112
-	 * @param Schema $targetSchema
113
-	 * @param \Doctrine\DBAL\Connection $connection
114
-	 * @return \Doctrine\DBAL\Schema\SchemaDiff
115
-	 * @throws DBALException
116
-	 */
117
-	protected function getDiff(Schema $targetSchema, \Doctrine\DBAL\Connection $connection) {
118
-		$schemaDiff = parent::getDiff($targetSchema, $connection);
119
-
120
-		// oracle forces us to quote the identifiers
121
-		$schemaDiff->newTables = array_map(function (Table $table) {
122
-			return new Table(
123
-				$this->connection->quoteIdentifier($table->getName()),
124
-				array_map(function (Column $column) {
125
-					return $this->quoteColumn($column);
126
-				}, $table->getColumns()),
127
-				array_map(function (Index $index) {
128
-					return $this->quoteIndex($index);
129
-				}, $table->getIndexes()),
130
-				array_map(function (ForeignKeyConstraint $fck) {
131
-					return $this->quoteForeignKeyConstraint($fck);
132
-				}, $table->getForeignKeys()),
133
-				0,
134
-				$table->getOptions()
135
-			);
136
-		}, $schemaDiff->newTables);
137
-
138
-		$schemaDiff->removedTables = array_map(function (Table $table) {
139
-			return new Table(
140
-				$this->connection->quoteIdentifier($table->getName()),
141
-				$table->getColumns(),
142
-				$table->getIndexes(),
143
-				$table->getForeignKeys(),
144
-				0,
145
-				$table->getOptions()
146
-			);
147
-		}, $schemaDiff->removedTables);
148
-
149
-		foreach ($schemaDiff->changedTables as $tableDiff) {
150
-			$tableDiff->name = $this->connection->quoteIdentifier($tableDiff->name);
151
-
152
-			$tableDiff->addedColumns = array_map(function (Column $column) {
153
-				return $this->quoteColumn($column);
154
-			}, $tableDiff->addedColumns);
155
-
156
-			foreach ($tableDiff->changedColumns as $column) {
157
-				$column->oldColumnName = $this->connection->quoteIdentifier($column->oldColumnName);
158
-				// auto increment is not relevant for oracle and can anyhow not be applied on change
159
-				$column->changedProperties = array_diff($column->changedProperties, ['autoincrement', 'unsigned']);
160
-			}
161
-			// remove columns that no longer have changed (because autoincrement and unsigned are not supported)
162
-			$tableDiff->changedColumns = array_filter($tableDiff->changedColumns, function (ColumnDiff $column) {
163
-				return count($column->changedProperties) > 0;
164
-			});
165
-
166
-			$tableDiff->removedColumns = array_map(function (Column $column) {
167
-				return $this->quoteColumn($column);
168
-			}, $tableDiff->removedColumns);
169
-
170
-			$tableDiff->renamedColumns = array_map(function (Column $column) {
171
-				return $this->quoteColumn($column);
172
-			}, $tableDiff->renamedColumns);
173
-
174
-			$tableDiff->addedIndexes = array_map(function (Index $index) {
175
-				return $this->quoteIndex($index);
176
-			}, $tableDiff->addedIndexes);
177
-
178
-			$tableDiff->changedIndexes = array_map(function (Index $index) {
179
-				return $this->quoteIndex($index);
180
-			}, $tableDiff->changedIndexes);
181
-
182
-			$tableDiff->removedIndexes = array_map(function (Index $index) {
183
-				return $this->quoteIndex($index);
184
-			}, $tableDiff->removedIndexes);
185
-
186
-			$tableDiff->renamedIndexes = array_map(function (Index $index) {
187
-				return $this->quoteIndex($index);
188
-			}, $tableDiff->renamedIndexes);
189
-
190
-			$tableDiff->addedForeignKeys = array_map(function (ForeignKeyConstraint $fkc) {
191
-				return $this->quoteForeignKeyConstraint($fkc);
192
-			}, $tableDiff->addedForeignKeys);
193
-
194
-			$tableDiff->changedForeignKeys = array_map(function (ForeignKeyConstraint $fkc) {
195
-				return $this->quoteForeignKeyConstraint($fkc);
196
-			}, $tableDiff->changedForeignKeys);
197
-
198
-			$tableDiff->removedForeignKeys = array_map(function (ForeignKeyConstraint $fkc) {
199
-				return $this->quoteForeignKeyConstraint($fkc);
200
-			}, $tableDiff->removedForeignKeys);
201
-		}
202
-
203
-		return $schemaDiff;
204
-	}
205
-
206
-	/**
207
-	 * @param string $name
208
-	 * @return string
209
-	 */
210
-	protected function generateTemporaryTableName($name) {
211
-		return 'oc_' . uniqid();
212
-	}
213
-
214
-	/**
215
-	 * @param $statement
216
-	 * @return string
217
-	 */
218
-	protected function convertStatementToScript($statement) {
219
-		if (substr($statement, -1) === ';') {
220
-			return $statement . PHP_EOL . '/' . PHP_EOL;
221
-		}
222
-		$script = $statement . ';';
223
-		$script .= PHP_EOL;
224
-		$script .= PHP_EOL;
225
-		return $script;
226
-	}
227
-
228
-	protected function getFilterExpression() {
229
-		return '/^"' . preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')) . '/';
230
-	}
42
+    /**
43
+     * Quote a column's name but changing the name requires recreating
44
+     * the column instance and copying over all properties.
45
+     *
46
+     * @param Column $column old column
47
+     * @return Column new column instance with new name
48
+     */
49
+    protected function quoteColumn(Column $column) {
50
+        $newColumn = new Column(
51
+            $this->connection->quoteIdentifier($column->getName()),
52
+            $column->getType()
53
+        );
54
+        $newColumn->setAutoincrement($column->getAutoincrement());
55
+        $newColumn->setColumnDefinition($column->getColumnDefinition());
56
+        $newColumn->setComment($column->getComment());
57
+        $newColumn->setDefault($column->getDefault());
58
+        $newColumn->setFixed($column->getFixed());
59
+        $newColumn->setLength($column->getLength());
60
+        $newColumn->setNotnull($column->getNotnull());
61
+        $newColumn->setPrecision($column->getPrecision());
62
+        $newColumn->setScale($column->getScale());
63
+        $newColumn->setUnsigned($column->getUnsigned());
64
+        $newColumn->setPlatformOptions($column->getPlatformOptions());
65
+        $newColumn->setCustomSchemaOptions($column->getPlatformOptions());
66
+        return $newColumn;
67
+    }
68
+
69
+    /**
70
+     * Quote an index's name but changing the name requires recreating
71
+     * the index instance and copying over all properties.
72
+     *
73
+     * @param Index $index old index
74
+     * @return Index new index instance with new name
75
+     */
76
+    protected function quoteIndex($index) {
77
+        return new Index(
78
+        //TODO migrate existing uppercase indexes, then $this->connection->quoteIdentifier($index->getName()),
79
+            $index->getName(),
80
+            array_map(function ($columnName) {
81
+                return $this->connection->quoteIdentifier($columnName);
82
+            }, $index->getColumns()),
83
+            $index->isUnique(),
84
+            $index->isPrimary(),
85
+            $index->getFlags(),
86
+            $index->getOptions()
87
+        );
88
+    }
89
+
90
+    /**
91
+     * Quote an ForeignKeyConstraint's name but changing the name requires recreating
92
+     * the ForeignKeyConstraint instance and copying over all properties.
93
+     *
94
+     * @param ForeignKeyConstraint $fkc old fkc
95
+     * @return ForeignKeyConstraint new fkc instance with new name
96
+     */
97
+    protected function quoteForeignKeyConstraint($fkc) {
98
+        return new ForeignKeyConstraint(
99
+            array_map(function ($columnName) {
100
+                return $this->connection->quoteIdentifier($columnName);
101
+            }, $fkc->getLocalColumns()),
102
+            $this->connection->quoteIdentifier($fkc->getForeignTableName()),
103
+            array_map(function ($columnName) {
104
+                return $this->connection->quoteIdentifier($columnName);
105
+            }, $fkc->getForeignColumns()),
106
+            $fkc->getName(),
107
+            $fkc->getOptions()
108
+        );
109
+    }
110
+
111
+    /**
112
+     * @param Schema $targetSchema
113
+     * @param \Doctrine\DBAL\Connection $connection
114
+     * @return \Doctrine\DBAL\Schema\SchemaDiff
115
+     * @throws DBALException
116
+     */
117
+    protected function getDiff(Schema $targetSchema, \Doctrine\DBAL\Connection $connection) {
118
+        $schemaDiff = parent::getDiff($targetSchema, $connection);
119
+
120
+        // oracle forces us to quote the identifiers
121
+        $schemaDiff->newTables = array_map(function (Table $table) {
122
+            return new Table(
123
+                $this->connection->quoteIdentifier($table->getName()),
124
+                array_map(function (Column $column) {
125
+                    return $this->quoteColumn($column);
126
+                }, $table->getColumns()),
127
+                array_map(function (Index $index) {
128
+                    return $this->quoteIndex($index);
129
+                }, $table->getIndexes()),
130
+                array_map(function (ForeignKeyConstraint $fck) {
131
+                    return $this->quoteForeignKeyConstraint($fck);
132
+                }, $table->getForeignKeys()),
133
+                0,
134
+                $table->getOptions()
135
+            );
136
+        }, $schemaDiff->newTables);
137
+
138
+        $schemaDiff->removedTables = array_map(function (Table $table) {
139
+            return new Table(
140
+                $this->connection->quoteIdentifier($table->getName()),
141
+                $table->getColumns(),
142
+                $table->getIndexes(),
143
+                $table->getForeignKeys(),
144
+                0,
145
+                $table->getOptions()
146
+            );
147
+        }, $schemaDiff->removedTables);
148
+
149
+        foreach ($schemaDiff->changedTables as $tableDiff) {
150
+            $tableDiff->name = $this->connection->quoteIdentifier($tableDiff->name);
151
+
152
+            $tableDiff->addedColumns = array_map(function (Column $column) {
153
+                return $this->quoteColumn($column);
154
+            }, $tableDiff->addedColumns);
155
+
156
+            foreach ($tableDiff->changedColumns as $column) {
157
+                $column->oldColumnName = $this->connection->quoteIdentifier($column->oldColumnName);
158
+                // auto increment is not relevant for oracle and can anyhow not be applied on change
159
+                $column->changedProperties = array_diff($column->changedProperties, ['autoincrement', 'unsigned']);
160
+            }
161
+            // remove columns that no longer have changed (because autoincrement and unsigned are not supported)
162
+            $tableDiff->changedColumns = array_filter($tableDiff->changedColumns, function (ColumnDiff $column) {
163
+                return count($column->changedProperties) > 0;
164
+            });
165
+
166
+            $tableDiff->removedColumns = array_map(function (Column $column) {
167
+                return $this->quoteColumn($column);
168
+            }, $tableDiff->removedColumns);
169
+
170
+            $tableDiff->renamedColumns = array_map(function (Column $column) {
171
+                return $this->quoteColumn($column);
172
+            }, $tableDiff->renamedColumns);
173
+
174
+            $tableDiff->addedIndexes = array_map(function (Index $index) {
175
+                return $this->quoteIndex($index);
176
+            }, $tableDiff->addedIndexes);
177
+
178
+            $tableDiff->changedIndexes = array_map(function (Index $index) {
179
+                return $this->quoteIndex($index);
180
+            }, $tableDiff->changedIndexes);
181
+
182
+            $tableDiff->removedIndexes = array_map(function (Index $index) {
183
+                return $this->quoteIndex($index);
184
+            }, $tableDiff->removedIndexes);
185
+
186
+            $tableDiff->renamedIndexes = array_map(function (Index $index) {
187
+                return $this->quoteIndex($index);
188
+            }, $tableDiff->renamedIndexes);
189
+
190
+            $tableDiff->addedForeignKeys = array_map(function (ForeignKeyConstraint $fkc) {
191
+                return $this->quoteForeignKeyConstraint($fkc);
192
+            }, $tableDiff->addedForeignKeys);
193
+
194
+            $tableDiff->changedForeignKeys = array_map(function (ForeignKeyConstraint $fkc) {
195
+                return $this->quoteForeignKeyConstraint($fkc);
196
+            }, $tableDiff->changedForeignKeys);
197
+
198
+            $tableDiff->removedForeignKeys = array_map(function (ForeignKeyConstraint $fkc) {
199
+                return $this->quoteForeignKeyConstraint($fkc);
200
+            }, $tableDiff->removedForeignKeys);
201
+        }
202
+
203
+        return $schemaDiff;
204
+    }
205
+
206
+    /**
207
+     * @param string $name
208
+     * @return string
209
+     */
210
+    protected function generateTemporaryTableName($name) {
211
+        return 'oc_' . uniqid();
212
+    }
213
+
214
+    /**
215
+     * @param $statement
216
+     * @return string
217
+     */
218
+    protected function convertStatementToScript($statement) {
219
+        if (substr($statement, -1) === ';') {
220
+            return $statement . PHP_EOL . '/' . PHP_EOL;
221
+        }
222
+        $script = $statement . ';';
223
+        $script .= PHP_EOL;
224
+        $script .= PHP_EOL;
225
+        return $script;
226
+    }
227
+
228
+    protected function getFilterExpression() {
229
+        return '/^"' . preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')) . '/';
230
+    }
231 231
 
232 232
 }
Please login to merge, or discard this patch.
Spacing   +23 added lines, -23 removed lines patch added patch discarded remove patch
@@ -77,7 +77,7 @@  discard block
 block discarded – undo
77 77
 		return new Index(
78 78
 		//TODO migrate existing uppercase indexes, then $this->connection->quoteIdentifier($index->getName()),
79 79
 			$index->getName(),
80
-			array_map(function ($columnName) {
80
+			array_map(function($columnName) {
81 81
 				return $this->connection->quoteIdentifier($columnName);
82 82
 			}, $index->getColumns()),
83 83
 			$index->isUnique(),
@@ -96,11 +96,11 @@  discard block
 block discarded – undo
96 96
 	 */
97 97
 	protected function quoteForeignKeyConstraint($fkc) {
98 98
 		return new ForeignKeyConstraint(
99
-			array_map(function ($columnName) {
99
+			array_map(function($columnName) {
100 100
 				return $this->connection->quoteIdentifier($columnName);
101 101
 			}, $fkc->getLocalColumns()),
102 102
 			$this->connection->quoteIdentifier($fkc->getForeignTableName()),
103
-			array_map(function ($columnName) {
103
+			array_map(function($columnName) {
104 104
 				return $this->connection->quoteIdentifier($columnName);
105 105
 			}, $fkc->getForeignColumns()),
106 106
 			$fkc->getName(),
@@ -118,16 +118,16 @@  discard block
 block discarded – undo
118 118
 		$schemaDiff = parent::getDiff($targetSchema, $connection);
119 119
 
120 120
 		// oracle forces us to quote the identifiers
121
-		$schemaDiff->newTables = array_map(function (Table $table) {
121
+		$schemaDiff->newTables = array_map(function(Table $table) {
122 122
 			return new Table(
123 123
 				$this->connection->quoteIdentifier($table->getName()),
124
-				array_map(function (Column $column) {
124
+				array_map(function(Column $column) {
125 125
 					return $this->quoteColumn($column);
126 126
 				}, $table->getColumns()),
127
-				array_map(function (Index $index) {
127
+				array_map(function(Index $index) {
128 128
 					return $this->quoteIndex($index);
129 129
 				}, $table->getIndexes()),
130
-				array_map(function (ForeignKeyConstraint $fck) {
130
+				array_map(function(ForeignKeyConstraint $fck) {
131 131
 					return $this->quoteForeignKeyConstraint($fck);
132 132
 				}, $table->getForeignKeys()),
133 133
 				0,
@@ -135,7 +135,7 @@  discard block
 block discarded – undo
135 135
 			);
136 136
 		}, $schemaDiff->newTables);
137 137
 
138
-		$schemaDiff->removedTables = array_map(function (Table $table) {
138
+		$schemaDiff->removedTables = array_map(function(Table $table) {
139 139
 			return new Table(
140 140
 				$this->connection->quoteIdentifier($table->getName()),
141 141
 				$table->getColumns(),
@@ -149,7 +149,7 @@  discard block
 block discarded – undo
149 149
 		foreach ($schemaDiff->changedTables as $tableDiff) {
150 150
 			$tableDiff->name = $this->connection->quoteIdentifier($tableDiff->name);
151 151
 
152
-			$tableDiff->addedColumns = array_map(function (Column $column) {
152
+			$tableDiff->addedColumns = array_map(function(Column $column) {
153 153
 				return $this->quoteColumn($column);
154 154
 			}, $tableDiff->addedColumns);
155 155
 
@@ -159,43 +159,43 @@  discard block
 block discarded – undo
159 159
 				$column->changedProperties = array_diff($column->changedProperties, ['autoincrement', 'unsigned']);
160 160
 			}
161 161
 			// remove columns that no longer have changed (because autoincrement and unsigned are not supported)
162
-			$tableDiff->changedColumns = array_filter($tableDiff->changedColumns, function (ColumnDiff $column) {
162
+			$tableDiff->changedColumns = array_filter($tableDiff->changedColumns, function(ColumnDiff $column) {
163 163
 				return count($column->changedProperties) > 0;
164 164
 			});
165 165
 
166
-			$tableDiff->removedColumns = array_map(function (Column $column) {
166
+			$tableDiff->removedColumns = array_map(function(Column $column) {
167 167
 				return $this->quoteColumn($column);
168 168
 			}, $tableDiff->removedColumns);
169 169
 
170
-			$tableDiff->renamedColumns = array_map(function (Column $column) {
170
+			$tableDiff->renamedColumns = array_map(function(Column $column) {
171 171
 				return $this->quoteColumn($column);
172 172
 			}, $tableDiff->renamedColumns);
173 173
 
174
-			$tableDiff->addedIndexes = array_map(function (Index $index) {
174
+			$tableDiff->addedIndexes = array_map(function(Index $index) {
175 175
 				return $this->quoteIndex($index);
176 176
 			}, $tableDiff->addedIndexes);
177 177
 
178
-			$tableDiff->changedIndexes = array_map(function (Index $index) {
178
+			$tableDiff->changedIndexes = array_map(function(Index $index) {
179 179
 				return $this->quoteIndex($index);
180 180
 			}, $tableDiff->changedIndexes);
181 181
 
182
-			$tableDiff->removedIndexes = array_map(function (Index $index) {
182
+			$tableDiff->removedIndexes = array_map(function(Index $index) {
183 183
 				return $this->quoteIndex($index);
184 184
 			}, $tableDiff->removedIndexes);
185 185
 
186
-			$tableDiff->renamedIndexes = array_map(function (Index $index) {
186
+			$tableDiff->renamedIndexes = array_map(function(Index $index) {
187 187
 				return $this->quoteIndex($index);
188 188
 			}, $tableDiff->renamedIndexes);
189 189
 
190
-			$tableDiff->addedForeignKeys = array_map(function (ForeignKeyConstraint $fkc) {
190
+			$tableDiff->addedForeignKeys = array_map(function(ForeignKeyConstraint $fkc) {
191 191
 				return $this->quoteForeignKeyConstraint($fkc);
192 192
 			}, $tableDiff->addedForeignKeys);
193 193
 
194
-			$tableDiff->changedForeignKeys = array_map(function (ForeignKeyConstraint $fkc) {
194
+			$tableDiff->changedForeignKeys = array_map(function(ForeignKeyConstraint $fkc) {
195 195
 				return $this->quoteForeignKeyConstraint($fkc);
196 196
 			}, $tableDiff->changedForeignKeys);
197 197
 
198
-			$tableDiff->removedForeignKeys = array_map(function (ForeignKeyConstraint $fkc) {
198
+			$tableDiff->removedForeignKeys = array_map(function(ForeignKeyConstraint $fkc) {
199 199
 				return $this->quoteForeignKeyConstraint($fkc);
200 200
 			}, $tableDiff->removedForeignKeys);
201 201
 		}
@@ -208,7 +208,7 @@  discard block
 block discarded – undo
208 208
 	 * @return string
209 209
 	 */
210 210
 	protected function generateTemporaryTableName($name) {
211
-		return 'oc_' . uniqid();
211
+		return 'oc_'.uniqid();
212 212
 	}
213 213
 
214 214
 	/**
@@ -217,16 +217,16 @@  discard block
 block discarded – undo
217 217
 	 */
218 218
 	protected function convertStatementToScript($statement) {
219 219
 		if (substr($statement, -1) === ';') {
220
-			return $statement . PHP_EOL . '/' . PHP_EOL;
220
+			return $statement.PHP_EOL.'/'.PHP_EOL;
221 221
 		}
222
-		$script = $statement . ';';
222
+		$script = $statement.';';
223 223
 		$script .= PHP_EOL;
224 224
 		$script .= PHP_EOL;
225 225
 		return $script;
226 226
 	}
227 227
 
228 228
 	protected function getFilterExpression() {
229
-		return '/^"' . preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')) . '/';
229
+		return '/^"'.preg_quote($this->config->getSystemValue('dbtableprefix', 'oc_')).'/';
230 230
 	}
231 231
 
232 232
 }
Please login to merge, or discard this patch.
lib/private/Updater.php 2 patches
Indentation   +566 added lines, -566 removed lines patch added patch discarded remove patch
@@ -57,571 +57,571 @@
 block discarded – undo
57 57
  */
58 58
 class Updater extends BasicEmitter {
59 59
 
60
-	/** @var ILogger $log */
61
-	private $log;
62
-
63
-	/** @var IConfig */
64
-	private $config;
65
-
66
-	/** @var Checker */
67
-	private $checker;
68
-
69
-	/** @var Installer */
70
-	private $installer;
71
-
72
-	private $logLevelNames = [
73
-		0 => 'Debug',
74
-		1 => 'Info',
75
-		2 => 'Warning',
76
-		3 => 'Error',
77
-		4 => 'Fatal',
78
-	];
79
-
80
-	/**
81
-	 * @param IConfig $config
82
-	 * @param Checker $checker
83
-	 * @param ILogger $log
84
-	 * @param Installer $installer
85
-	 */
86
-	public function __construct(IConfig $config,
87
-								Checker $checker,
88
-								ILogger $log = null,
89
-								Installer $installer) {
90
-		$this->log = $log;
91
-		$this->config = $config;
92
-		$this->checker = $checker;
93
-		$this->installer = $installer;
94
-	}
95
-
96
-	/**
97
-	 * runs the update actions in maintenance mode, does not upgrade the source files
98
-	 * except the main .htaccess file
99
-	 *
100
-	 * @return bool true if the operation succeeded, false otherwise
101
-	 */
102
-	public function upgrade() {
103
-		$this->emitRepairEvents();
104
-		$this->logAllEvents();
105
-
106
-		$logLevel = $this->config->getSystemValue('loglevel', ILogger::WARN);
107
-		$this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
108
-		$this->config->setSystemValue('loglevel', ILogger::DEBUG);
109
-
110
-		$wasMaintenanceModeEnabled = $this->config->getSystemValueBool('maintenance');
111
-
112
-		if(!$wasMaintenanceModeEnabled) {
113
-			$this->config->setSystemValue('maintenance', true);
114
-			$this->emit('\OC\Updater', 'maintenanceEnabled');
115
-		}
116
-
117
-		// Clear CAN_INSTALL file if not on git
118
-		if (\OC_Util::getChannel() !== 'git' && is_file(\OC::$configDir.'/CAN_INSTALL')) {
119
-			if (!unlink(\OC::$configDir . '/CAN_INSTALL')) {
120
-				$this->log->error('Could not cleanup CAN_INSTALL from your config folder. Please remove this file manually.');
121
-			}
122
-		}
123
-
124
-		$installedVersion = $this->config->getSystemValue('version', '0.0.0');
125
-		$currentVersion = implode('.', \OCP\Util::getVersion());
126
-
127
-		$this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, ['app' => 'core']);
128
-
129
-		$success = true;
130
-		try {
131
-			$this->doUpgrade($currentVersion, $installedVersion);
132
-		} catch (HintException $exception) {
133
-			$this->log->logException($exception, ['app' => 'core']);
134
-			$this->emit('\OC\Updater', 'failure', [$exception->getMessage() . ': ' .$exception->getHint()]);
135
-			$success = false;
136
-		} catch (\Exception $exception) {
137
-			$this->log->logException($exception, ['app' => 'core']);
138
-			$this->emit('\OC\Updater', 'failure', [get_class($exception) . ': ' .$exception->getMessage()]);
139
-			$success = false;
140
-		}
141
-
142
-		$this->emit('\OC\Updater', 'updateEnd', [$success]);
143
-
144
-		if(!$wasMaintenanceModeEnabled && $success) {
145
-			$this->config->setSystemValue('maintenance', false);
146
-			$this->emit('\OC\Updater', 'maintenanceDisabled');
147
-		} else {
148
-			$this->emit('\OC\Updater', 'maintenanceActive');
149
-		}
150
-
151
-		$this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
152
-		$this->config->setSystemValue('loglevel', $logLevel);
153
-		$this->config->setSystemValue('installed', true);
154
-
155
-		return $success;
156
-	}
157
-
158
-	/**
159
-	 * Return version from which this version is allowed to upgrade from
160
-	 *
161
-	 * @return array allowed previous versions per vendor
162
-	 */
163
-	private function getAllowedPreviousVersions() {
164
-		// this should really be a JSON file
165
-		require \OC::$SERVERROOT . '/version.php';
166
-		/** @var array $OC_VersionCanBeUpgradedFrom */
167
-		return $OC_VersionCanBeUpgradedFrom;
168
-	}
169
-
170
-	/**
171
-	 * Return vendor from which this version was published
172
-	 *
173
-	 * @return string Get the vendor
174
-	 */
175
-	private function getVendor() {
176
-		// this should really be a JSON file
177
-		require \OC::$SERVERROOT . '/version.php';
178
-		/** @var string $vendor */
179
-		return (string) $vendor;
180
-	}
181
-
182
-	/**
183
-	 * Whether an upgrade to a specified version is possible
184
-	 * @param string $oldVersion
185
-	 * @param string $newVersion
186
-	 * @param array $allowedPreviousVersions
187
-	 * @return bool
188
-	 */
189
-	public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) {
190
-		$version = explode('.', $oldVersion);
191
-		$majorMinor = $version[0] . '.' . $version[1];
192
-
193
-		$currentVendor = $this->config->getAppValue('core', 'vendor', '');
194
-
195
-		// Vendor was not set correctly on install, so we have to white-list known versions
196
-		if ($currentVendor === '' && isset($allowedPreviousVersions['owncloud'][$oldVersion])) {
197
-			$currentVendor = 'owncloud';
198
-		}
199
-
200
-		if ($currentVendor === 'nextcloud') {
201
-			return isset($allowedPreviousVersions[$currentVendor][$majorMinor])
202
-				&& (version_compare($oldVersion, $newVersion, '<=') ||
203
-					$this->config->getSystemValue('debug', false));
204
-		}
205
-
206
-		// Check if the instance can be migrated
207
-		return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) ||
208
-			isset($allowedPreviousVersions[$currentVendor][$oldVersion]);
209
-	}
210
-
211
-	/**
212
-	 * runs the update actions in maintenance mode, does not upgrade the source files
213
-	 * except the main .htaccess file
214
-	 *
215
-	 * @param string $currentVersion current version to upgrade to
216
-	 * @param string $installedVersion previous version from which to upgrade from
217
-	 *
218
-	 * @throws \Exception
219
-	 */
220
-	private function doUpgrade($currentVersion, $installedVersion) {
221
-		// Stop update if the update is over several major versions
222
-		$allowedPreviousVersions = $this->getAllowedPreviousVersions();
223
-		if (!$this->isUpgradePossible($installedVersion, $currentVersion, $allowedPreviousVersions)) {
224
-			throw new \Exception('Updates between multiple major versions and downgrades are unsupported.');
225
-		}
226
-
227
-		// Update .htaccess files
228
-		try {
229
-			Setup::updateHtaccess();
230
-			Setup::protectDataDirectory();
231
-		} catch (\Exception $e) {
232
-			throw new \Exception($e->getMessage());
233
-		}
234
-
235
-		// create empty file in data dir, so we can later find
236
-		// out that this is indeed an ownCloud data directory
237
-		// (in case it didn't exist before)
238
-		file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', '');
239
-
240
-		// pre-upgrade repairs
241
-		$repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher());
242
-		$repair->run();
243
-
244
-		$this->doCoreUpgrade();
245
-
246
-		try {
247
-			// TODO: replace with the new repair step mechanism https://github.com/owncloud/core/pull/24378
248
-			Setup::installBackgroundJobs();
249
-		} catch (\Exception $e) {
250
-			throw new \Exception($e->getMessage());
251
-		}
252
-
253
-		// update all shipped apps
254
-		$this->checkAppsRequirements();
255
-		$this->doAppUpgrade();
256
-
257
-		// Update the appfetchers version so it downloads the correct list from the appstore
258
-		\OC::$server->getAppFetcher()->setVersion($currentVersion);
259
-
260
-		// upgrade appstore apps
261
-		$this->upgradeAppStoreApps(\OC::$server->getAppManager()->getInstalledApps());
262
-		$autoDisabledApps = \OC::$server->getAppManager()->getAutoDisabledApps();
263
-		$this->upgradeAppStoreApps($autoDisabledApps, true);
264
-
265
-		// install new shipped apps on upgrade
266
-		OC_App::loadApps(['authentication']);
267
-		$errors = Installer::installShippedApps(true);
268
-		foreach ($errors as $appId => $exception) {
269
-			/** @var \Exception $exception */
270
-			$this->log->logException($exception, ['app' => $appId]);
271
-			$this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]);
272
-		}
273
-
274
-		// post-upgrade repairs
275
-		$repair = new Repair(Repair::getRepairSteps(), \OC::$server->getEventDispatcher());
276
-		$repair->run();
277
-
278
-		//Invalidate update feed
279
-		$this->config->setAppValue('core', 'lastupdatedat', 0);
280
-
281
-		// Check for code integrity if not disabled
282
-		if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
283
-			$this->emit('\OC\Updater', 'startCheckCodeIntegrity');
284
-			$this->checker->runInstanceVerification();
285
-			$this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
286
-		}
287
-
288
-		// only set the final version if everything went well
289
-		$this->config->setSystemValue('version', implode('.', Util::getVersion()));
290
-		$this->config->setAppValue('core', 'vendor', $this->getVendor());
291
-	}
292
-
293
-	protected function doCoreUpgrade() {
294
-		$this->emit('\OC\Updater', 'dbUpgradeBefore');
295
-
296
-		// execute core migrations
297
-		$ms = new MigrationService('core', \OC::$server->getDatabaseConnection());
298
-		$ms->migrate();
299
-
300
-		$this->emit('\OC\Updater', 'dbUpgrade');
301
-	}
302
-
303
-	/**
304
-	 * @param string $version the oc version to check app compatibility with
305
-	 */
306
-	protected function checkAppUpgrade($version) {
307
-		$apps = \OC_App::getEnabledApps();
308
-		$this->emit('\OC\Updater', 'appUpgradeCheckBefore');
309
-
310
-		$appManager = \OC::$server->getAppManager();
311
-		foreach ($apps as $appId) {
312
-			$info = \OC_App::getAppInfo($appId);
313
-			$compatible = \OC_App::isAppCompatible($version, $info);
314
-			$isShipped = $appManager->isShipped($appId);
315
-
316
-			if ($compatible && $isShipped && \OC_App::shouldUpgrade($appId)) {
317
-				/**
318
-				 * FIXME: The preupdate check is performed before the database migration, otherwise database changes
319
-				 * are not possible anymore within it. - Consider this when touching the code.
320
-				 * @link https://github.com/owncloud/core/issues/10980
321
-				 * @see \OC_App::updateApp
322
-				 */
323
-				if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/preupdate.php')) {
324
-					$this->includePreUpdate($appId);
325
-				}
326
-				if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) {
327
-					$this->emit('\OC\Updater', 'appSimulateUpdate', [$appId]);
328
-					\OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml');
329
-				}
330
-			}
331
-		}
332
-
333
-		$this->emit('\OC\Updater', 'appUpgradeCheck');
334
-	}
335
-
336
-	/**
337
-	 * Includes the pre-update file. Done here to prevent namespace mixups.
338
-	 * @param string $appId
339
-	 */
340
-	private function includePreUpdate($appId) {
341
-		include \OC_App::getAppPath($appId) . '/appinfo/preupdate.php';
342
-	}
343
-
344
-	/**
345
-	 * upgrades all apps within a major ownCloud upgrade. Also loads "priority"
346
-	 * (types authentication, filesystem, logging, in that order) afterwards.
347
-	 *
348
-	 * @throws NeedsUpdateException
349
-	 */
350
-	protected function doAppUpgrade() {
351
-		$apps = \OC_App::getEnabledApps();
352
-		$priorityTypes = ['authentication', 'filesystem', 'logging'];
353
-		$pseudoOtherType = 'other';
354
-		$stacks = [$pseudoOtherType => []];
355
-
356
-		foreach ($apps as $appId) {
357
-			$priorityType = false;
358
-			foreach ($priorityTypes as $type) {
359
-				if(!isset($stacks[$type])) {
360
-					$stacks[$type] = [];
361
-				}
362
-				if (\OC_App::isType($appId, [$type])) {
363
-					$stacks[$type][] = $appId;
364
-					$priorityType = true;
365
-					break;
366
-				}
367
-			}
368
-			if (!$priorityType) {
369
-				$stacks[$pseudoOtherType][] = $appId;
370
-			}
371
-		}
372
-		foreach ($stacks as $type => $stack) {
373
-			foreach ($stack as $appId) {
374
-				if (\OC_App::shouldUpgrade($appId)) {
375
-					$this->emit('\OC\Updater', 'appUpgradeStarted', [$appId, \OC_App::getAppVersion($appId)]);
376
-					\OC_App::updateApp($appId);
377
-					$this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]);
378
-				}
379
-				if($type !== $pseudoOtherType) {
380
-					// load authentication, filesystem and logging apps after
381
-					// upgrading them. Other apps my need to rely on modifying
382
-					// user and/or filesystem aspects.
383
-					\OC_App::loadApp($appId);
384
-				}
385
-			}
386
-		}
387
-	}
388
-
389
-	/**
390
-	 * check if the current enabled apps are compatible with the current
391
-	 * ownCloud version. disable them if not.
392
-	 * This is important if you upgrade ownCloud and have non ported 3rd
393
-	 * party apps installed.
394
-	 *
395
-	 * @return array
396
-	 * @throws \Exception
397
-	 */
398
-	private function checkAppsRequirements() {
399
-		$isCoreUpgrade = $this->isCodeUpgrade();
400
-		$apps = OC_App::getEnabledApps();
401
-		$version = implode('.', Util::getVersion());
402
-		$disabledApps = [];
403
-		$appManager = \OC::$server->getAppManager();
404
-		foreach ($apps as $app) {
405
-			// check if the app is compatible with this version of ownCloud
406
-			$info = OC_App::getAppInfo($app);
407
-			if($info === null || !OC_App::isAppCompatible($version, $info)) {
408
-				if ($appManager->isShipped($app)) {
409
-					throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update');
410
-				}
411
-				\OC::$server->getAppManager()->disableApp($app, true);
412
-				$this->emit('\OC\Updater', 'incompatibleAppDisabled', [$app]);
413
-			}
414
-			// no need to disable any app in case this is a non-core upgrade
415
-			if (!$isCoreUpgrade) {
416
-				continue;
417
-			}
418
-			// shipped apps will remain enabled
419
-			if ($appManager->isShipped($app)) {
420
-				continue;
421
-			}
422
-			// authentication and session apps will remain enabled as well
423
-			if (OC_App::isType($app, ['session', 'authentication'])) {
424
-				continue;
425
-			}
426
-		}
427
-		return $disabledApps;
428
-	}
429
-
430
-	/**
431
-	 * @return bool
432
-	 */
433
-	private function isCodeUpgrade() {
434
-		$installedVersion = $this->config->getSystemValue('version', '0.0.0');
435
-		$currentVersion = implode('.', Util::getVersion());
436
-		if (version_compare($currentVersion, $installedVersion, '>')) {
437
-			return true;
438
-		}
439
-		return false;
440
-	}
441
-
442
-	/**
443
-	 * @param array $disabledApps
444
-	 * @param bool $reenable
445
-	 * @throws \Exception
446
-	 */
447
-	private function upgradeAppStoreApps(array $disabledApps, $reenable = false) {
448
-		foreach($disabledApps as $app) {
449
-			try {
450
-				$this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]);
451
-				if ($this->installer->isUpdateAvailable($app)) {
452
-					$this->emit('\OC\Updater', 'upgradeAppStoreApp', [$app]);
453
-					$this->installer->updateAppstoreApp($app);
454
-				}
455
-				$this->emit('\OC\Updater', 'checkAppStoreApp', [$app]);
456
-
457
-				if ($reenable) {
458
-					$ocApp = new \OC_App();
459
-					$ocApp->enable($app);
460
-				}
461
-			} catch (\Exception $ex) {
462
-				$this->log->logException($ex, ['app' => 'core']);
463
-			}
464
-		}
465
-	}
466
-
467
-	/**
468
-	 * Forward messages emitted by the repair routine
469
-	 */
470
-	private function emitRepairEvents() {
471
-		$dispatcher = \OC::$server->getEventDispatcher();
472
-		$dispatcher->addListener('\OC\Repair::warning', function ($event) {
473
-			if ($event instanceof GenericEvent) {
474
-				$this->emit('\OC\Updater', 'repairWarning', $event->getArguments());
475
-			}
476
-		});
477
-		$dispatcher->addListener('\OC\Repair::error', function ($event) {
478
-			if ($event instanceof GenericEvent) {
479
-				$this->emit('\OC\Updater', 'repairError', $event->getArguments());
480
-			}
481
-		});
482
-		$dispatcher->addListener('\OC\Repair::info', function ($event) {
483
-			if ($event instanceof GenericEvent) {
484
-				$this->emit('\OC\Updater', 'repairInfo', $event->getArguments());
485
-			}
486
-		});
487
-		$dispatcher->addListener('\OC\Repair::step', function ($event) {
488
-			if ($event instanceof GenericEvent) {
489
-				$this->emit('\OC\Updater', 'repairStep', $event->getArguments());
490
-			}
491
-		});
492
-	}
493
-
494
-	private function logAllEvents() {
495
-		$log = $this->log;
496
-
497
-		$dispatcher = \OC::$server->getEventDispatcher();
498
-		$dispatcher->addListener('\OC\DB\Migrator::executeSql', function ($event) use ($log) {
499
-			if (!$event instanceof GenericEvent) {
500
-				return;
501
-			}
502
-			$log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
503
-		});
504
-		$dispatcher->addListener('\OC\DB\Migrator::checkTable', function ($event) use ($log) {
505
-			if (!$event instanceof GenericEvent) {
506
-				return;
507
-			}
508
-			$log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
509
-		});
510
-
511
-		$repairListener = function ($event) use ($log) {
512
-			if (!$event instanceof GenericEvent) {
513
-				return;
514
-			}
515
-			switch ($event->getSubject()) {
516
-				case '\OC\Repair::startProgress':
517
-					$log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) .  ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
518
-					break;
519
-				case '\OC\Repair::advance':
520
-					$desc = $event->getArgument(1);
521
-					if (empty($desc)) {
522
-						$desc = '';
523
-					}
524
-					$log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
525
-
526
-					break;
527
-				case '\OC\Repair::finishProgress':
528
-					$log->info('\OC\Repair::finishProgress', ['app' => 'updater']);
529
-					break;
530
-				case '\OC\Repair::step':
531
-					$log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']);
532
-					break;
533
-				case '\OC\Repair::info':
534
-					$log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']);
535
-					break;
536
-				case '\OC\Repair::warning':
537
-					$log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']);
538
-					break;
539
-				case '\OC\Repair::error':
540
-					$log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']);
541
-					break;
542
-			}
543
-		};
544
-
545
-		$dispatcher->addListener('\OC\Repair::startProgress', $repairListener);
546
-		$dispatcher->addListener('\OC\Repair::advance', $repairListener);
547
-		$dispatcher->addListener('\OC\Repair::finishProgress', $repairListener);
548
-		$dispatcher->addListener('\OC\Repair::step', $repairListener);
549
-		$dispatcher->addListener('\OC\Repair::info', $repairListener);
550
-		$dispatcher->addListener('\OC\Repair::warning', $repairListener);
551
-		$dispatcher->addListener('\OC\Repair::error', $repairListener);
552
-
553
-
554
-		$this->listen('\OC\Updater', 'maintenanceEnabled', function () use ($log) {
555
-			$log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']);
556
-		});
557
-		$this->listen('\OC\Updater', 'maintenanceDisabled', function () use ($log) {
558
-			$log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']);
559
-		});
560
-		$this->listen('\OC\Updater', 'maintenanceActive', function () use ($log) {
561
-			$log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']);
562
-		});
563
-		$this->listen('\OC\Updater', 'updateEnd', function ($success) use ($log) {
564
-			if ($success) {
565
-				$log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']);
566
-			} else {
567
-				$log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']);
568
-			}
569
-		});
570
-		$this->listen('\OC\Updater', 'dbUpgradeBefore', function () use ($log) {
571
-			$log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']);
572
-		});
573
-		$this->listen('\OC\Updater', 'dbUpgrade', function () use ($log) {
574
-			$log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']);
575
-		});
576
-		$this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use ($log) {
577
-			$log->info('\OC\Updater::dbSimulateUpgradeBefore: Checking whether the database schema can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
578
-		});
579
-		$this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use ($log) {
580
-			$log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']);
581
-		});
582
-		$this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use ($log) {
583
-			$log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']);
584
-		});
585
-		$this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use ($log) {
586
-			$log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']);
587
-		});
588
-		$this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use ($log) {
589
-			$log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']);
590
-		});
591
-		$this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use ($log) {
592
-			$log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']);
593
-		});
594
-		$this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) {
595
-			$log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']);
596
-		});
597
-		$this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) {
598
-			$log->info('\OC\Updater::appSimulateUpdate: Checking whether the database schema for <' . $app . '> can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
599
-		});
600
-		$this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) {
601
-			$log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']);
602
-		});
603
-		$this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) {
604
-			$log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']);
605
-		});
606
-		$this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) {
607
-			$log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']);
608
-		});
609
-		$this->listen('\OC\Updater', 'failure', function ($message) use ($log) {
610
-			$log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']);
611
-		});
612
-		$this->listen('\OC\Updater', 'setDebugLogLevel', function () use ($log) {
613
-			$log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']);
614
-		});
615
-		$this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use ($log) {
616
-			$log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']);
617
-		});
618
-		$this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use ($log) {
619
-			$log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']);
620
-		});
621
-		$this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use ($log) {
622
-			$log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']);
623
-		});
624
-
625
-	}
60
+    /** @var ILogger $log */
61
+    private $log;
62
+
63
+    /** @var IConfig */
64
+    private $config;
65
+
66
+    /** @var Checker */
67
+    private $checker;
68
+
69
+    /** @var Installer */
70
+    private $installer;
71
+
72
+    private $logLevelNames = [
73
+        0 => 'Debug',
74
+        1 => 'Info',
75
+        2 => 'Warning',
76
+        3 => 'Error',
77
+        4 => 'Fatal',
78
+    ];
79
+
80
+    /**
81
+     * @param IConfig $config
82
+     * @param Checker $checker
83
+     * @param ILogger $log
84
+     * @param Installer $installer
85
+     */
86
+    public function __construct(IConfig $config,
87
+                                Checker $checker,
88
+                                ILogger $log = null,
89
+                                Installer $installer) {
90
+        $this->log = $log;
91
+        $this->config = $config;
92
+        $this->checker = $checker;
93
+        $this->installer = $installer;
94
+    }
95
+
96
+    /**
97
+     * runs the update actions in maintenance mode, does not upgrade the source files
98
+     * except the main .htaccess file
99
+     *
100
+     * @return bool true if the operation succeeded, false otherwise
101
+     */
102
+    public function upgrade() {
103
+        $this->emitRepairEvents();
104
+        $this->logAllEvents();
105
+
106
+        $logLevel = $this->config->getSystemValue('loglevel', ILogger::WARN);
107
+        $this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
108
+        $this->config->setSystemValue('loglevel', ILogger::DEBUG);
109
+
110
+        $wasMaintenanceModeEnabled = $this->config->getSystemValueBool('maintenance');
111
+
112
+        if(!$wasMaintenanceModeEnabled) {
113
+            $this->config->setSystemValue('maintenance', true);
114
+            $this->emit('\OC\Updater', 'maintenanceEnabled');
115
+        }
116
+
117
+        // Clear CAN_INSTALL file if not on git
118
+        if (\OC_Util::getChannel() !== 'git' && is_file(\OC::$configDir.'/CAN_INSTALL')) {
119
+            if (!unlink(\OC::$configDir . '/CAN_INSTALL')) {
120
+                $this->log->error('Could not cleanup CAN_INSTALL from your config folder. Please remove this file manually.');
121
+            }
122
+        }
123
+
124
+        $installedVersion = $this->config->getSystemValue('version', '0.0.0');
125
+        $currentVersion = implode('.', \OCP\Util::getVersion());
126
+
127
+        $this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, ['app' => 'core']);
128
+
129
+        $success = true;
130
+        try {
131
+            $this->doUpgrade($currentVersion, $installedVersion);
132
+        } catch (HintException $exception) {
133
+            $this->log->logException($exception, ['app' => 'core']);
134
+            $this->emit('\OC\Updater', 'failure', [$exception->getMessage() . ': ' .$exception->getHint()]);
135
+            $success = false;
136
+        } catch (\Exception $exception) {
137
+            $this->log->logException($exception, ['app' => 'core']);
138
+            $this->emit('\OC\Updater', 'failure', [get_class($exception) . ': ' .$exception->getMessage()]);
139
+            $success = false;
140
+        }
141
+
142
+        $this->emit('\OC\Updater', 'updateEnd', [$success]);
143
+
144
+        if(!$wasMaintenanceModeEnabled && $success) {
145
+            $this->config->setSystemValue('maintenance', false);
146
+            $this->emit('\OC\Updater', 'maintenanceDisabled');
147
+        } else {
148
+            $this->emit('\OC\Updater', 'maintenanceActive');
149
+        }
150
+
151
+        $this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
152
+        $this->config->setSystemValue('loglevel', $logLevel);
153
+        $this->config->setSystemValue('installed', true);
154
+
155
+        return $success;
156
+    }
157
+
158
+    /**
159
+     * Return version from which this version is allowed to upgrade from
160
+     *
161
+     * @return array allowed previous versions per vendor
162
+     */
163
+    private function getAllowedPreviousVersions() {
164
+        // this should really be a JSON file
165
+        require \OC::$SERVERROOT . '/version.php';
166
+        /** @var array $OC_VersionCanBeUpgradedFrom */
167
+        return $OC_VersionCanBeUpgradedFrom;
168
+    }
169
+
170
+    /**
171
+     * Return vendor from which this version was published
172
+     *
173
+     * @return string Get the vendor
174
+     */
175
+    private function getVendor() {
176
+        // this should really be a JSON file
177
+        require \OC::$SERVERROOT . '/version.php';
178
+        /** @var string $vendor */
179
+        return (string) $vendor;
180
+    }
181
+
182
+    /**
183
+     * Whether an upgrade to a specified version is possible
184
+     * @param string $oldVersion
185
+     * @param string $newVersion
186
+     * @param array $allowedPreviousVersions
187
+     * @return bool
188
+     */
189
+    public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) {
190
+        $version = explode('.', $oldVersion);
191
+        $majorMinor = $version[0] . '.' . $version[1];
192
+
193
+        $currentVendor = $this->config->getAppValue('core', 'vendor', '');
194
+
195
+        // Vendor was not set correctly on install, so we have to white-list known versions
196
+        if ($currentVendor === '' && isset($allowedPreviousVersions['owncloud'][$oldVersion])) {
197
+            $currentVendor = 'owncloud';
198
+        }
199
+
200
+        if ($currentVendor === 'nextcloud') {
201
+            return isset($allowedPreviousVersions[$currentVendor][$majorMinor])
202
+                && (version_compare($oldVersion, $newVersion, '<=') ||
203
+                    $this->config->getSystemValue('debug', false));
204
+        }
205
+
206
+        // Check if the instance can be migrated
207
+        return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) ||
208
+            isset($allowedPreviousVersions[$currentVendor][$oldVersion]);
209
+    }
210
+
211
+    /**
212
+     * runs the update actions in maintenance mode, does not upgrade the source files
213
+     * except the main .htaccess file
214
+     *
215
+     * @param string $currentVersion current version to upgrade to
216
+     * @param string $installedVersion previous version from which to upgrade from
217
+     *
218
+     * @throws \Exception
219
+     */
220
+    private function doUpgrade($currentVersion, $installedVersion) {
221
+        // Stop update if the update is over several major versions
222
+        $allowedPreviousVersions = $this->getAllowedPreviousVersions();
223
+        if (!$this->isUpgradePossible($installedVersion, $currentVersion, $allowedPreviousVersions)) {
224
+            throw new \Exception('Updates between multiple major versions and downgrades are unsupported.');
225
+        }
226
+
227
+        // Update .htaccess files
228
+        try {
229
+            Setup::updateHtaccess();
230
+            Setup::protectDataDirectory();
231
+        } catch (\Exception $e) {
232
+            throw new \Exception($e->getMessage());
233
+        }
234
+
235
+        // create empty file in data dir, so we can later find
236
+        // out that this is indeed an ownCloud data directory
237
+        // (in case it didn't exist before)
238
+        file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', '');
239
+
240
+        // pre-upgrade repairs
241
+        $repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher());
242
+        $repair->run();
243
+
244
+        $this->doCoreUpgrade();
245
+
246
+        try {
247
+            // TODO: replace with the new repair step mechanism https://github.com/owncloud/core/pull/24378
248
+            Setup::installBackgroundJobs();
249
+        } catch (\Exception $e) {
250
+            throw new \Exception($e->getMessage());
251
+        }
252
+
253
+        // update all shipped apps
254
+        $this->checkAppsRequirements();
255
+        $this->doAppUpgrade();
256
+
257
+        // Update the appfetchers version so it downloads the correct list from the appstore
258
+        \OC::$server->getAppFetcher()->setVersion($currentVersion);
259
+
260
+        // upgrade appstore apps
261
+        $this->upgradeAppStoreApps(\OC::$server->getAppManager()->getInstalledApps());
262
+        $autoDisabledApps = \OC::$server->getAppManager()->getAutoDisabledApps();
263
+        $this->upgradeAppStoreApps($autoDisabledApps, true);
264
+
265
+        // install new shipped apps on upgrade
266
+        OC_App::loadApps(['authentication']);
267
+        $errors = Installer::installShippedApps(true);
268
+        foreach ($errors as $appId => $exception) {
269
+            /** @var \Exception $exception */
270
+            $this->log->logException($exception, ['app' => $appId]);
271
+            $this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]);
272
+        }
273
+
274
+        // post-upgrade repairs
275
+        $repair = new Repair(Repair::getRepairSteps(), \OC::$server->getEventDispatcher());
276
+        $repair->run();
277
+
278
+        //Invalidate update feed
279
+        $this->config->setAppValue('core', 'lastupdatedat', 0);
280
+
281
+        // Check for code integrity if not disabled
282
+        if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
283
+            $this->emit('\OC\Updater', 'startCheckCodeIntegrity');
284
+            $this->checker->runInstanceVerification();
285
+            $this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
286
+        }
287
+
288
+        // only set the final version if everything went well
289
+        $this->config->setSystemValue('version', implode('.', Util::getVersion()));
290
+        $this->config->setAppValue('core', 'vendor', $this->getVendor());
291
+    }
292
+
293
+    protected function doCoreUpgrade() {
294
+        $this->emit('\OC\Updater', 'dbUpgradeBefore');
295
+
296
+        // execute core migrations
297
+        $ms = new MigrationService('core', \OC::$server->getDatabaseConnection());
298
+        $ms->migrate();
299
+
300
+        $this->emit('\OC\Updater', 'dbUpgrade');
301
+    }
302
+
303
+    /**
304
+     * @param string $version the oc version to check app compatibility with
305
+     */
306
+    protected function checkAppUpgrade($version) {
307
+        $apps = \OC_App::getEnabledApps();
308
+        $this->emit('\OC\Updater', 'appUpgradeCheckBefore');
309
+
310
+        $appManager = \OC::$server->getAppManager();
311
+        foreach ($apps as $appId) {
312
+            $info = \OC_App::getAppInfo($appId);
313
+            $compatible = \OC_App::isAppCompatible($version, $info);
314
+            $isShipped = $appManager->isShipped($appId);
315
+
316
+            if ($compatible && $isShipped && \OC_App::shouldUpgrade($appId)) {
317
+                /**
318
+                 * FIXME: The preupdate check is performed before the database migration, otherwise database changes
319
+                 * are not possible anymore within it. - Consider this when touching the code.
320
+                 * @link https://github.com/owncloud/core/issues/10980
321
+                 * @see \OC_App::updateApp
322
+                 */
323
+                if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/preupdate.php')) {
324
+                    $this->includePreUpdate($appId);
325
+                }
326
+                if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) {
327
+                    $this->emit('\OC\Updater', 'appSimulateUpdate', [$appId]);
328
+                    \OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml');
329
+                }
330
+            }
331
+        }
332
+
333
+        $this->emit('\OC\Updater', 'appUpgradeCheck');
334
+    }
335
+
336
+    /**
337
+     * Includes the pre-update file. Done here to prevent namespace mixups.
338
+     * @param string $appId
339
+     */
340
+    private function includePreUpdate($appId) {
341
+        include \OC_App::getAppPath($appId) . '/appinfo/preupdate.php';
342
+    }
343
+
344
+    /**
345
+     * upgrades all apps within a major ownCloud upgrade. Also loads "priority"
346
+     * (types authentication, filesystem, logging, in that order) afterwards.
347
+     *
348
+     * @throws NeedsUpdateException
349
+     */
350
+    protected function doAppUpgrade() {
351
+        $apps = \OC_App::getEnabledApps();
352
+        $priorityTypes = ['authentication', 'filesystem', 'logging'];
353
+        $pseudoOtherType = 'other';
354
+        $stacks = [$pseudoOtherType => []];
355
+
356
+        foreach ($apps as $appId) {
357
+            $priorityType = false;
358
+            foreach ($priorityTypes as $type) {
359
+                if(!isset($stacks[$type])) {
360
+                    $stacks[$type] = [];
361
+                }
362
+                if (\OC_App::isType($appId, [$type])) {
363
+                    $stacks[$type][] = $appId;
364
+                    $priorityType = true;
365
+                    break;
366
+                }
367
+            }
368
+            if (!$priorityType) {
369
+                $stacks[$pseudoOtherType][] = $appId;
370
+            }
371
+        }
372
+        foreach ($stacks as $type => $stack) {
373
+            foreach ($stack as $appId) {
374
+                if (\OC_App::shouldUpgrade($appId)) {
375
+                    $this->emit('\OC\Updater', 'appUpgradeStarted', [$appId, \OC_App::getAppVersion($appId)]);
376
+                    \OC_App::updateApp($appId);
377
+                    $this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]);
378
+                }
379
+                if($type !== $pseudoOtherType) {
380
+                    // load authentication, filesystem and logging apps after
381
+                    // upgrading them. Other apps my need to rely on modifying
382
+                    // user and/or filesystem aspects.
383
+                    \OC_App::loadApp($appId);
384
+                }
385
+            }
386
+        }
387
+    }
388
+
389
+    /**
390
+     * check if the current enabled apps are compatible with the current
391
+     * ownCloud version. disable them if not.
392
+     * This is important if you upgrade ownCloud and have non ported 3rd
393
+     * party apps installed.
394
+     *
395
+     * @return array
396
+     * @throws \Exception
397
+     */
398
+    private function checkAppsRequirements() {
399
+        $isCoreUpgrade = $this->isCodeUpgrade();
400
+        $apps = OC_App::getEnabledApps();
401
+        $version = implode('.', Util::getVersion());
402
+        $disabledApps = [];
403
+        $appManager = \OC::$server->getAppManager();
404
+        foreach ($apps as $app) {
405
+            // check if the app is compatible with this version of ownCloud
406
+            $info = OC_App::getAppInfo($app);
407
+            if($info === null || !OC_App::isAppCompatible($version, $info)) {
408
+                if ($appManager->isShipped($app)) {
409
+                    throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update');
410
+                }
411
+                \OC::$server->getAppManager()->disableApp($app, true);
412
+                $this->emit('\OC\Updater', 'incompatibleAppDisabled', [$app]);
413
+            }
414
+            // no need to disable any app in case this is a non-core upgrade
415
+            if (!$isCoreUpgrade) {
416
+                continue;
417
+            }
418
+            // shipped apps will remain enabled
419
+            if ($appManager->isShipped($app)) {
420
+                continue;
421
+            }
422
+            // authentication and session apps will remain enabled as well
423
+            if (OC_App::isType($app, ['session', 'authentication'])) {
424
+                continue;
425
+            }
426
+        }
427
+        return $disabledApps;
428
+    }
429
+
430
+    /**
431
+     * @return bool
432
+     */
433
+    private function isCodeUpgrade() {
434
+        $installedVersion = $this->config->getSystemValue('version', '0.0.0');
435
+        $currentVersion = implode('.', Util::getVersion());
436
+        if (version_compare($currentVersion, $installedVersion, '>')) {
437
+            return true;
438
+        }
439
+        return false;
440
+    }
441
+
442
+    /**
443
+     * @param array $disabledApps
444
+     * @param bool $reenable
445
+     * @throws \Exception
446
+     */
447
+    private function upgradeAppStoreApps(array $disabledApps, $reenable = false) {
448
+        foreach($disabledApps as $app) {
449
+            try {
450
+                $this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]);
451
+                if ($this->installer->isUpdateAvailable($app)) {
452
+                    $this->emit('\OC\Updater', 'upgradeAppStoreApp', [$app]);
453
+                    $this->installer->updateAppstoreApp($app);
454
+                }
455
+                $this->emit('\OC\Updater', 'checkAppStoreApp', [$app]);
456
+
457
+                if ($reenable) {
458
+                    $ocApp = new \OC_App();
459
+                    $ocApp->enable($app);
460
+                }
461
+            } catch (\Exception $ex) {
462
+                $this->log->logException($ex, ['app' => 'core']);
463
+            }
464
+        }
465
+    }
466
+
467
+    /**
468
+     * Forward messages emitted by the repair routine
469
+     */
470
+    private function emitRepairEvents() {
471
+        $dispatcher = \OC::$server->getEventDispatcher();
472
+        $dispatcher->addListener('\OC\Repair::warning', function ($event) {
473
+            if ($event instanceof GenericEvent) {
474
+                $this->emit('\OC\Updater', 'repairWarning', $event->getArguments());
475
+            }
476
+        });
477
+        $dispatcher->addListener('\OC\Repair::error', function ($event) {
478
+            if ($event instanceof GenericEvent) {
479
+                $this->emit('\OC\Updater', 'repairError', $event->getArguments());
480
+            }
481
+        });
482
+        $dispatcher->addListener('\OC\Repair::info', function ($event) {
483
+            if ($event instanceof GenericEvent) {
484
+                $this->emit('\OC\Updater', 'repairInfo', $event->getArguments());
485
+            }
486
+        });
487
+        $dispatcher->addListener('\OC\Repair::step', function ($event) {
488
+            if ($event instanceof GenericEvent) {
489
+                $this->emit('\OC\Updater', 'repairStep', $event->getArguments());
490
+            }
491
+        });
492
+    }
493
+
494
+    private function logAllEvents() {
495
+        $log = $this->log;
496
+
497
+        $dispatcher = \OC::$server->getEventDispatcher();
498
+        $dispatcher->addListener('\OC\DB\Migrator::executeSql', function ($event) use ($log) {
499
+            if (!$event instanceof GenericEvent) {
500
+                return;
501
+            }
502
+            $log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
503
+        });
504
+        $dispatcher->addListener('\OC\DB\Migrator::checkTable', function ($event) use ($log) {
505
+            if (!$event instanceof GenericEvent) {
506
+                return;
507
+            }
508
+            $log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
509
+        });
510
+
511
+        $repairListener = function ($event) use ($log) {
512
+            if (!$event instanceof GenericEvent) {
513
+                return;
514
+            }
515
+            switch ($event->getSubject()) {
516
+                case '\OC\Repair::startProgress':
517
+                    $log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) .  ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
518
+                    break;
519
+                case '\OC\Repair::advance':
520
+                    $desc = $event->getArgument(1);
521
+                    if (empty($desc)) {
522
+                        $desc = '';
523
+                    }
524
+                    $log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
525
+
526
+                    break;
527
+                case '\OC\Repair::finishProgress':
528
+                    $log->info('\OC\Repair::finishProgress', ['app' => 'updater']);
529
+                    break;
530
+                case '\OC\Repair::step':
531
+                    $log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']);
532
+                    break;
533
+                case '\OC\Repair::info':
534
+                    $log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']);
535
+                    break;
536
+                case '\OC\Repair::warning':
537
+                    $log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']);
538
+                    break;
539
+                case '\OC\Repair::error':
540
+                    $log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']);
541
+                    break;
542
+            }
543
+        };
544
+
545
+        $dispatcher->addListener('\OC\Repair::startProgress', $repairListener);
546
+        $dispatcher->addListener('\OC\Repair::advance', $repairListener);
547
+        $dispatcher->addListener('\OC\Repair::finishProgress', $repairListener);
548
+        $dispatcher->addListener('\OC\Repair::step', $repairListener);
549
+        $dispatcher->addListener('\OC\Repair::info', $repairListener);
550
+        $dispatcher->addListener('\OC\Repair::warning', $repairListener);
551
+        $dispatcher->addListener('\OC\Repair::error', $repairListener);
552
+
553
+
554
+        $this->listen('\OC\Updater', 'maintenanceEnabled', function () use ($log) {
555
+            $log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']);
556
+        });
557
+        $this->listen('\OC\Updater', 'maintenanceDisabled', function () use ($log) {
558
+            $log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']);
559
+        });
560
+        $this->listen('\OC\Updater', 'maintenanceActive', function () use ($log) {
561
+            $log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']);
562
+        });
563
+        $this->listen('\OC\Updater', 'updateEnd', function ($success) use ($log) {
564
+            if ($success) {
565
+                $log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']);
566
+            } else {
567
+                $log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']);
568
+            }
569
+        });
570
+        $this->listen('\OC\Updater', 'dbUpgradeBefore', function () use ($log) {
571
+            $log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']);
572
+        });
573
+        $this->listen('\OC\Updater', 'dbUpgrade', function () use ($log) {
574
+            $log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']);
575
+        });
576
+        $this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use ($log) {
577
+            $log->info('\OC\Updater::dbSimulateUpgradeBefore: Checking whether the database schema can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
578
+        });
579
+        $this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use ($log) {
580
+            $log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']);
581
+        });
582
+        $this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use ($log) {
583
+            $log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']);
584
+        });
585
+        $this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use ($log) {
586
+            $log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']);
587
+        });
588
+        $this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use ($log) {
589
+            $log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']);
590
+        });
591
+        $this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use ($log) {
592
+            $log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']);
593
+        });
594
+        $this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) {
595
+            $log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']);
596
+        });
597
+        $this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) {
598
+            $log->info('\OC\Updater::appSimulateUpdate: Checking whether the database schema for <' . $app . '> can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
599
+        });
600
+        $this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) {
601
+            $log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']);
602
+        });
603
+        $this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) {
604
+            $log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']);
605
+        });
606
+        $this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) {
607
+            $log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']);
608
+        });
609
+        $this->listen('\OC\Updater', 'failure', function ($message) use ($log) {
610
+            $log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']);
611
+        });
612
+        $this->listen('\OC\Updater', 'setDebugLogLevel', function () use ($log) {
613
+            $log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']);
614
+        });
615
+        $this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use ($log) {
616
+            $log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']);
617
+        });
618
+        $this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use ($log) {
619
+            $log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']);
620
+        });
621
+        $this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use ($log) {
622
+            $log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']);
623
+        });
624
+
625
+    }
626 626
 
627 627
 }
Please login to merge, or discard this patch.
Spacing   +69 added lines, -69 removed lines patch added patch discarded remove patch
@@ -104,19 +104,19 @@  discard block
 block discarded – undo
104 104
 		$this->logAllEvents();
105 105
 
106 106
 		$logLevel = $this->config->getSystemValue('loglevel', ILogger::WARN);
107
-		$this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
107
+		$this->emit('\OC\Updater', 'setDebugLogLevel', [$logLevel, $this->logLevelNames[$logLevel]]);
108 108
 		$this->config->setSystemValue('loglevel', ILogger::DEBUG);
109 109
 
110 110
 		$wasMaintenanceModeEnabled = $this->config->getSystemValueBool('maintenance');
111 111
 
112
-		if(!$wasMaintenanceModeEnabled) {
112
+		if (!$wasMaintenanceModeEnabled) {
113 113
 			$this->config->setSystemValue('maintenance', true);
114 114
 			$this->emit('\OC\Updater', 'maintenanceEnabled');
115 115
 		}
116 116
 
117 117
 		// Clear CAN_INSTALL file if not on git
118 118
 		if (\OC_Util::getChannel() !== 'git' && is_file(\OC::$configDir.'/CAN_INSTALL')) {
119
-			if (!unlink(\OC::$configDir . '/CAN_INSTALL')) {
119
+			if (!unlink(\OC::$configDir.'/CAN_INSTALL')) {
120 120
 				$this->log->error('Could not cleanup CAN_INSTALL from your config folder. Please remove this file manually.');
121 121
 			}
122 122
 		}
@@ -124,31 +124,31 @@  discard block
 block discarded – undo
124 124
 		$installedVersion = $this->config->getSystemValue('version', '0.0.0');
125 125
 		$currentVersion = implode('.', \OCP\Util::getVersion());
126 126
 
127
-		$this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, ['app' => 'core']);
127
+		$this->log->debug('starting upgrade from '.$installedVersion.' to '.$currentVersion, ['app' => 'core']);
128 128
 
129 129
 		$success = true;
130 130
 		try {
131 131
 			$this->doUpgrade($currentVersion, $installedVersion);
132 132
 		} catch (HintException $exception) {
133 133
 			$this->log->logException($exception, ['app' => 'core']);
134
-			$this->emit('\OC\Updater', 'failure', [$exception->getMessage() . ': ' .$exception->getHint()]);
134
+			$this->emit('\OC\Updater', 'failure', [$exception->getMessage().': '.$exception->getHint()]);
135 135
 			$success = false;
136 136
 		} catch (\Exception $exception) {
137 137
 			$this->log->logException($exception, ['app' => 'core']);
138
-			$this->emit('\OC\Updater', 'failure', [get_class($exception) . ': ' .$exception->getMessage()]);
138
+			$this->emit('\OC\Updater', 'failure', [get_class($exception).': '.$exception->getMessage()]);
139 139
 			$success = false;
140 140
 		}
141 141
 
142 142
 		$this->emit('\OC\Updater', 'updateEnd', [$success]);
143 143
 
144
-		if(!$wasMaintenanceModeEnabled && $success) {
144
+		if (!$wasMaintenanceModeEnabled && $success) {
145 145
 			$this->config->setSystemValue('maintenance', false);
146 146
 			$this->emit('\OC\Updater', 'maintenanceDisabled');
147 147
 		} else {
148 148
 			$this->emit('\OC\Updater', 'maintenanceActive');
149 149
 		}
150 150
 
151
-		$this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
151
+		$this->emit('\OC\Updater', 'resetLogLevel', [$logLevel, $this->logLevelNames[$logLevel]]);
152 152
 		$this->config->setSystemValue('loglevel', $logLevel);
153 153
 		$this->config->setSystemValue('installed', true);
154 154
 
@@ -162,7 +162,7 @@  discard block
 block discarded – undo
162 162
 	 */
163 163
 	private function getAllowedPreviousVersions() {
164 164
 		// this should really be a JSON file
165
-		require \OC::$SERVERROOT . '/version.php';
165
+		require \OC::$SERVERROOT.'/version.php';
166 166
 		/** @var array $OC_VersionCanBeUpgradedFrom */
167 167
 		return $OC_VersionCanBeUpgradedFrom;
168 168
 	}
@@ -174,7 +174,7 @@  discard block
 block discarded – undo
174 174
 	 */
175 175
 	private function getVendor() {
176 176
 		// this should really be a JSON file
177
-		require \OC::$SERVERROOT . '/version.php';
177
+		require \OC::$SERVERROOT.'/version.php';
178 178
 		/** @var string $vendor */
179 179
 		return (string) $vendor;
180 180
 	}
@@ -188,7 +188,7 @@  discard block
 block discarded – undo
188 188
 	 */
189 189
 	public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) {
190 190
 		$version = explode('.', $oldVersion);
191
-		$majorMinor = $version[0] . '.' . $version[1];
191
+		$majorMinor = $version[0].'.'.$version[1];
192 192
 
193 193
 		$currentVendor = $this->config->getAppValue('core', 'vendor', '');
194 194
 
@@ -235,7 +235,7 @@  discard block
 block discarded – undo
235 235
 		// create empty file in data dir, so we can later find
236 236
 		// out that this is indeed an ownCloud data directory
237 237
 		// (in case it didn't exist before)
238
-		file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', '');
238
+		file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT.'/data').'/.ocdata', '');
239 239
 
240 240
 		// pre-upgrade repairs
241 241
 		$repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher());
@@ -268,7 +268,7 @@  discard block
 block discarded – undo
268 268
 		foreach ($errors as $appId => $exception) {
269 269
 			/** @var \Exception $exception */
270 270
 			$this->log->logException($exception, ['app' => $appId]);
271
-			$this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]);
271
+			$this->emit('\OC\Updater', 'failure', [$appId.': '.$exception->getMessage()]);
272 272
 		}
273 273
 
274 274
 		// post-upgrade repairs
@@ -279,7 +279,7 @@  discard block
 block discarded – undo
279 279
 		$this->config->setAppValue('core', 'lastupdatedat', 0);
280 280
 
281 281
 		// Check for code integrity if not disabled
282
-		if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
282
+		if (\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
283 283
 			$this->emit('\OC\Updater', 'startCheckCodeIntegrity');
284 284
 			$this->checker->runInstanceVerification();
285 285
 			$this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
@@ -320,12 +320,12 @@  discard block
 block discarded – undo
320 320
 				 * @link https://github.com/owncloud/core/issues/10980
321 321
 				 * @see \OC_App::updateApp
322 322
 				 */
323
-				if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/preupdate.php')) {
323
+				if (file_exists(\OC_App::getAppPath($appId).'/appinfo/preupdate.php')) {
324 324
 					$this->includePreUpdate($appId);
325 325
 				}
326
-				if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) {
326
+				if (file_exists(\OC_App::getAppPath($appId).'/appinfo/database.xml')) {
327 327
 					$this->emit('\OC\Updater', 'appSimulateUpdate', [$appId]);
328
-					\OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml');
328
+					\OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId).'/appinfo/database.xml');
329 329
 				}
330 330
 			}
331 331
 		}
@@ -338,7 +338,7 @@  discard block
 block discarded – undo
338 338
 	 * @param string $appId
339 339
 	 */
340 340
 	private function includePreUpdate($appId) {
341
-		include \OC_App::getAppPath($appId) . '/appinfo/preupdate.php';
341
+		include \OC_App::getAppPath($appId).'/appinfo/preupdate.php';
342 342
 	}
343 343
 
344 344
 	/**
@@ -356,7 +356,7 @@  discard block
 block discarded – undo
356 356
 		foreach ($apps as $appId) {
357 357
 			$priorityType = false;
358 358
 			foreach ($priorityTypes as $type) {
359
-				if(!isset($stacks[$type])) {
359
+				if (!isset($stacks[$type])) {
360 360
 					$stacks[$type] = [];
361 361
 				}
362 362
 				if (\OC_App::isType($appId, [$type])) {
@@ -376,7 +376,7 @@  discard block
 block discarded – undo
376 376
 					\OC_App::updateApp($appId);
377 377
 					$this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]);
378 378
 				}
379
-				if($type !== $pseudoOtherType) {
379
+				if ($type !== $pseudoOtherType) {
380 380
 					// load authentication, filesystem and logging apps after
381 381
 					// upgrading them. Other apps my need to rely on modifying
382 382
 					// user and/or filesystem aspects.
@@ -404,9 +404,9 @@  discard block
 block discarded – undo
404 404
 		foreach ($apps as $app) {
405 405
 			// check if the app is compatible with this version of ownCloud
406 406
 			$info = OC_App::getAppInfo($app);
407
-			if($info === null || !OC_App::isAppCompatible($version, $info)) {
407
+			if ($info === null || !OC_App::isAppCompatible($version, $info)) {
408 408
 				if ($appManager->isShipped($app)) {
409
-					throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update');
409
+					throw new \UnexpectedValueException('The files of the app "'.$app.'" were not correctly replaced before running the update');
410 410
 				}
411 411
 				\OC::$server->getAppManager()->disableApp($app, true);
412 412
 				$this->emit('\OC\Updater', 'incompatibleAppDisabled', [$app]);
@@ -445,7 +445,7 @@  discard block
 block discarded – undo
445 445
 	 * @throws \Exception
446 446
 	 */
447 447
 	private function upgradeAppStoreApps(array $disabledApps, $reenable = false) {
448
-		foreach($disabledApps as $app) {
448
+		foreach ($disabledApps as $app) {
449 449
 			try {
450 450
 				$this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]);
451 451
 				if ($this->installer->isUpdateAvailable($app)) {
@@ -469,22 +469,22 @@  discard block
 block discarded – undo
469 469
 	 */
470 470
 	private function emitRepairEvents() {
471 471
 		$dispatcher = \OC::$server->getEventDispatcher();
472
-		$dispatcher->addListener('\OC\Repair::warning', function ($event) {
472
+		$dispatcher->addListener('\OC\Repair::warning', function($event) {
473 473
 			if ($event instanceof GenericEvent) {
474 474
 				$this->emit('\OC\Updater', 'repairWarning', $event->getArguments());
475 475
 			}
476 476
 		});
477
-		$dispatcher->addListener('\OC\Repair::error', function ($event) {
477
+		$dispatcher->addListener('\OC\Repair::error', function($event) {
478 478
 			if ($event instanceof GenericEvent) {
479 479
 				$this->emit('\OC\Updater', 'repairError', $event->getArguments());
480 480
 			}
481 481
 		});
482
-		$dispatcher->addListener('\OC\Repair::info', function ($event) {
482
+		$dispatcher->addListener('\OC\Repair::info', function($event) {
483 483
 			if ($event instanceof GenericEvent) {
484 484
 				$this->emit('\OC\Updater', 'repairInfo', $event->getArguments());
485 485
 			}
486 486
 		});
487
-		$dispatcher->addListener('\OC\Repair::step', function ($event) {
487
+		$dispatcher->addListener('\OC\Repair::step', function($event) {
488 488
 			if ($event instanceof GenericEvent) {
489 489
 				$this->emit('\OC\Updater', 'repairStep', $event->getArguments());
490 490
 			}
@@ -495,49 +495,49 @@  discard block
 block discarded – undo
495 495
 		$log = $this->log;
496 496
 
497 497
 		$dispatcher = \OC::$server->getEventDispatcher();
498
-		$dispatcher->addListener('\OC\DB\Migrator::executeSql', function ($event) use ($log) {
498
+		$dispatcher->addListener('\OC\DB\Migrator::executeSql', function($event) use ($log) {
499 499
 			if (!$event instanceof GenericEvent) {
500 500
 				return;
501 501
 			}
502
-			$log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
502
+			$log->info('\OC\DB\Migrator::executeSql: '.$event->getSubject().' ('.$event->getArgument(0).' of '.$event->getArgument(1).')', ['app' => 'updater']);
503 503
 		});
504
-		$dispatcher->addListener('\OC\DB\Migrator::checkTable', function ($event) use ($log) {
504
+		$dispatcher->addListener('\OC\DB\Migrator::checkTable', function($event) use ($log) {
505 505
 			if (!$event instanceof GenericEvent) {
506 506
 				return;
507 507
 			}
508
-			$log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
508
+			$log->info('\OC\DB\Migrator::checkTable: '.$event->getSubject().' ('.$event->getArgument(0).' of '.$event->getArgument(1).')', ['app' => 'updater']);
509 509
 		});
510 510
 
511
-		$repairListener = function ($event) use ($log) {
511
+		$repairListener = function($event) use ($log) {
512 512
 			if (!$event instanceof GenericEvent) {
513 513
 				return;
514 514
 			}
515 515
 			switch ($event->getSubject()) {
516 516
 				case '\OC\Repair::startProgress':
517
-					$log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) .  ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
517
+					$log->info('\OC\Repair::startProgress: Starting ... '.$event->getArgument(1).' ('.$event->getArgument(0).')', ['app' => 'updater']);
518 518
 					break;
519 519
 				case '\OC\Repair::advance':
520 520
 					$desc = $event->getArgument(1);
521 521
 					if (empty($desc)) {
522 522
 						$desc = '';
523 523
 					}
524
-					$log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
524
+					$log->info('\OC\Repair::advance: '.$desc.' ('.$event->getArgument(0).')', ['app' => 'updater']);
525 525
 
526 526
 					break;
527 527
 				case '\OC\Repair::finishProgress':
528 528
 					$log->info('\OC\Repair::finishProgress', ['app' => 'updater']);
529 529
 					break;
530 530
 				case '\OC\Repair::step':
531
-					$log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']);
531
+					$log->info('\OC\Repair::step: Repair step: '.$event->getArgument(0), ['app' => 'updater']);
532 532
 					break;
533 533
 				case '\OC\Repair::info':
534
-					$log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']);
534
+					$log->info('\OC\Repair::info: Repair info: '.$event->getArgument(0), ['app' => 'updater']);
535 535
 					break;
536 536
 				case '\OC\Repair::warning':
537
-					$log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']);
537
+					$log->warning('\OC\Repair::warning: Repair warning: '.$event->getArgument(0), ['app' => 'updater']);
538 538
 					break;
539 539
 				case '\OC\Repair::error':
540
-					$log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']);
540
+					$log->error('\OC\Repair::error: Repair error: '.$event->getArgument(0), ['app' => 'updater']);
541 541
 					break;
542 542
 			}
543 543
 		};
@@ -551,74 +551,74 @@  discard block
 block discarded – undo
551 551
 		$dispatcher->addListener('\OC\Repair::error', $repairListener);
552 552
 
553 553
 
554
-		$this->listen('\OC\Updater', 'maintenanceEnabled', function () use ($log) {
554
+		$this->listen('\OC\Updater', 'maintenanceEnabled', function() use ($log) {
555 555
 			$log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']);
556 556
 		});
557
-		$this->listen('\OC\Updater', 'maintenanceDisabled', function () use ($log) {
557
+		$this->listen('\OC\Updater', 'maintenanceDisabled', function() use ($log) {
558 558
 			$log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']);
559 559
 		});
560
-		$this->listen('\OC\Updater', 'maintenanceActive', function () use ($log) {
560
+		$this->listen('\OC\Updater', 'maintenanceActive', function() use ($log) {
561 561
 			$log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']);
562 562
 		});
563
-		$this->listen('\OC\Updater', 'updateEnd', function ($success) use ($log) {
563
+		$this->listen('\OC\Updater', 'updateEnd', function($success) use ($log) {
564 564
 			if ($success) {
565 565
 				$log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']);
566 566
 			} else {
567 567
 				$log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']);
568 568
 			}
569 569
 		});
570
-		$this->listen('\OC\Updater', 'dbUpgradeBefore', function () use ($log) {
570
+		$this->listen('\OC\Updater', 'dbUpgradeBefore', function() use ($log) {
571 571
 			$log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']);
572 572
 		});
573
-		$this->listen('\OC\Updater', 'dbUpgrade', function () use ($log) {
573
+		$this->listen('\OC\Updater', 'dbUpgrade', function() use ($log) {
574 574
 			$log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']);
575 575
 		});
576
-		$this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use ($log) {
576
+		$this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function() use ($log) {
577 577
 			$log->info('\OC\Updater::dbSimulateUpgradeBefore: Checking whether the database schema can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
578 578
 		});
579
-		$this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use ($log) {
579
+		$this->listen('\OC\Updater', 'dbSimulateUpgrade', function() use ($log) {
580 580
 			$log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']);
581 581
 		});
582
-		$this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use ($log) {
583
-			$log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']);
582
+		$this->listen('\OC\Updater', 'incompatibleAppDisabled', function($app) use ($log) {
583
+			$log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: '.$app, ['app' => 'updater']);
584 584
 		});
585
-		$this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use ($log) {
586
-			$log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']);
585
+		$this->listen('\OC\Updater', 'checkAppStoreAppBefore', function($app) use ($log) {
586
+			$log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "'.$app.'" in appstore', ['app' => 'updater']);
587 587
 		});
588
-		$this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use ($log) {
589
-			$log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']);
588
+		$this->listen('\OC\Updater', 'upgradeAppStoreApp', function($app) use ($log) {
589
+			$log->info('\OC\Updater::upgradeAppStoreApp: Update app "'.$app.'" from appstore', ['app' => 'updater']);
590 590
 		});
591
-		$this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use ($log) {
592
-			$log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']);
591
+		$this->listen('\OC\Updater', 'checkAppStoreApp', function($app) use ($log) {
592
+			$log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "'.$app.'" in appstore', ['app' => 'updater']);
593 593
 		});
594
-		$this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) {
594
+		$this->listen('\OC\Updater', 'appUpgradeCheckBefore', function() use ($log) {
595 595
 			$log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']);
596 596
 		});
597
-		$this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) {
598
-			$log->info('\OC\Updater::appSimulateUpdate: Checking whether the database schema for <' . $app . '> can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
597
+		$this->listen('\OC\Updater', 'appSimulateUpdate', function($app) use ($log) {
598
+			$log->info('\OC\Updater::appSimulateUpdate: Checking whether the database schema for <'.$app.'> can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
599 599
 		});
600
-		$this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) {
600
+		$this->listen('\OC\Updater', 'appUpgradeCheck', function() use ($log) {
601 601
 			$log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']);
602 602
 		});
603
-		$this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) {
604
-			$log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']);
603
+		$this->listen('\OC\Updater', 'appUpgradeStarted', function($app) use ($log) {
604
+			$log->info('\OC\Updater::appUpgradeStarted: Updating <'.$app.'> ...', ['app' => 'updater']);
605 605
 		});
606
-		$this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) {
607
-			$log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']);
606
+		$this->listen('\OC\Updater', 'appUpgrade', function($app, $version) use ($log) {
607
+			$log->info('\OC\Updater::appUpgrade: Updated <'.$app.'> to '.$version, ['app' => 'updater']);
608 608
 		});
609
-		$this->listen('\OC\Updater', 'failure', function ($message) use ($log) {
610
-			$log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']);
609
+		$this->listen('\OC\Updater', 'failure', function($message) use ($log) {
610
+			$log->error('\OC\Updater::failure: '.$message, ['app' => 'updater']);
611 611
 		});
612
-		$this->listen('\OC\Updater', 'setDebugLogLevel', function () use ($log) {
612
+		$this->listen('\OC\Updater', 'setDebugLogLevel', function() use ($log) {
613 613
 			$log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']);
614 614
 		});
615
-		$this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use ($log) {
616
-			$log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']);
615
+		$this->listen('\OC\Updater', 'resetLogLevel', function($logLevel, $logLevelName) use ($log) {
616
+			$log->info('\OC\Updater::resetLogLevel: Reset log level to '.$logLevelName.'('.$logLevel.')', ['app' => 'updater']);
617 617
 		});
618
-		$this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use ($log) {
618
+		$this->listen('\OC\Updater', 'startCheckCodeIntegrity', function() use ($log) {
619 619
 			$log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']);
620 620
 		});
621
-		$this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use ($log) {
621
+		$this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function() use ($log) {
622 622
 			$log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']);
623 623
 		});
624 624
 
Please login to merge, or discard this patch.
lib/private/Tags.php 2 patches
Indentation   +805 added lines, -805 removed lines patch added patch discarded remove patch
@@ -54,809 +54,809 @@
 block discarded – undo
54 54
 
55 55
 class Tags implements ITags {
56 56
 
57
-	/**
58
-	 * Tags
59
-	 *
60
-	 * @var array
61
-	 */
62
-	private $tags = [];
63
-
64
-	/**
65
-	 * Used for storing objectid/categoryname pairs while rescanning.
66
-	 *
67
-	 * @var array
68
-	 */
69
-	private static $relations = [];
70
-
71
-	/**
72
-	 * Type
73
-	 *
74
-	 * @var string
75
-	 */
76
-	private $type;
77
-
78
-	/**
79
-	 * User
80
-	 *
81
-	 * @var string
82
-	 */
83
-	private $user;
84
-
85
-	/**
86
-	 * Are we including tags for shared items?
87
-	 *
88
-	 * @var bool
89
-	 */
90
-	private $includeShared = false;
91
-
92
-	/**
93
-	 * The current user, plus any owners of the items shared with the current
94
-	 * user, if $this->includeShared === true.
95
-	 *
96
-	 * @var array
97
-	 */
98
-	private $owners = [];
99
-
100
-	/**
101
-	 * The Mapper we're using to communicate our Tag objects to the database.
102
-	 *
103
-	 * @var TagMapper
104
-	 */
105
-	private $mapper;
106
-
107
-	/**
108
-	 * The sharing backend for objects of $this->type. Required if
109
-	 * $this->includeShared === true to determine ownership of items.
110
-	 *
111
-	 * @var \OCP\Share_Backend
112
-	 */
113
-	private $backend;
114
-
115
-	const TAG_TABLE = '*PREFIX*vcategory';
116
-	const RELATION_TABLE = '*PREFIX*vcategory_to_object';
117
-
118
-	/**
119
-	 * Constructor.
120
-	 *
121
-	 * @param TagMapper $mapper Instance of the TagMapper abstraction layer.
122
-	 * @param string $user The user whose data the object will operate on.
123
-	 * @param string $type The type of items for which tags will be loaded.
124
-	 * @param array $defaultTags Tags that should be created at construction.
125
-	 * @param boolean $includeShared Whether to include tags for items shared with this user by others.
126
-	 */
127
-	public function __construct(TagMapper $mapper, $user, $type, $defaultTags = [], $includeShared = false) {
128
-		$this->mapper = $mapper;
129
-		$this->user = $user;
130
-		$this->type = $type;
131
-		$this->includeShared = $includeShared;
132
-		$this->owners = [$this->user];
133
-		if ($this->includeShared) {
134
-			$this->owners = array_merge($this->owners, \OC\Share\Share::getSharedItemsOwners($this->user, $this->type, true));
135
-			$this->backend = \OC\Share\Share::getBackend($this->type);
136
-		}
137
-		$this->tags = $this->mapper->loadTags($this->owners, $this->type);
138
-
139
-		if(count($defaultTags) > 0 && count($this->tags) === 0) {
140
-			$this->addMultiple($defaultTags, true);
141
-		}
142
-	}
143
-
144
-	/**
145
-	 * Check if any tags are saved for this type and user.
146
-	 *
147
-	 * @return boolean
148
-	 */
149
-	public function isEmpty() {
150
-		return count($this->tags) === 0;
151
-	}
152
-
153
-	/**
154
-	 * Returns an array mapping a given tag's properties to its values:
155
-	 * ['id' => 0, 'name' = 'Tag', 'owner' = 'User', 'type' => 'tagtype']
156
-	 *
157
-	 * @param string $id The ID of the tag that is going to be mapped
158
-	 * @return array|false
159
-	 */
160
-	public function getTag($id) {
161
-		$key = $this->getTagById($id);
162
-		if ($key !== false) {
163
-			return $this->tagMap($this->tags[$key]);
164
-		}
165
-		return false;
166
-	}
167
-
168
-	/**
169
-	 * Get the tags for a specific user.
170
-	 *
171
-	 * This returns an array with maps containing each tag's properties:
172
-	 * [
173
-	 * 	['id' => 0, 'name' = 'First tag', 'owner' = 'User', 'type' => 'tagtype'],
174
-	 * 	['id' => 1, 'name' = 'Shared tag', 'owner' = 'Other user', 'type' => 'tagtype'],
175
-	 * ]
176
-	 *
177
-	 * @return array
178
-	 */
179
-	public function getTags() {
180
-		if(!count($this->tags)) {
181
-			return [];
182
-		}
183
-
184
-		usort($this->tags, function ($a, $b) {
185
-			return strnatcasecmp($a->getName(), $b->getName());
186
-		});
187
-		$tagMap = [];
188
-
189
-		foreach($this->tags as $tag) {
190
-			if($tag->getName() !== ITags::TAG_FAVORITE) {
191
-				$tagMap[] = $this->tagMap($tag);
192
-			}
193
-		}
194
-		return $tagMap;
195
-
196
-	}
197
-
198
-	/**
199
-	 * Return only the tags owned by the given user, omitting any tags shared
200
-	 * by other users.
201
-	 *
202
-	 * @param string $user The user whose tags are to be checked.
203
-	 * @return array An array of Tag objects.
204
-	 */
205
-	public function getTagsForUser($user) {
206
-		return array_filter($this->tags,
207
-			function ($tag) use ($user) {
208
-				return $tag->getOwner() === $user;
209
-			}
210
-		);
211
-	}
212
-
213
-	/**
214
-	 * Get the list of tags for the given ids.
215
-	 *
216
-	 * @param array $objIds array of object ids
217
-	 * @return array|boolean of tags id as key to array of tag names
218
-	 * or false if an error occurred
219
-	 */
220
-	public function getTagsForObjects(array $objIds) {
221
-		$entries = [];
222
-
223
-		try {
224
-			$conn = \OC::$server->getDatabaseConnection();
225
-			$chunks = array_chunk($objIds, 900, false);
226
-			foreach ($chunks as $chunk) {
227
-				$result = $conn->executeQuery(
228
-					'SELECT `category`, `categoryid`, `objid` ' .
229
-					'FROM `' . self::RELATION_TABLE . '` r, `' . self::TAG_TABLE . '` ' .
230
-					'WHERE `categoryid` = `id` AND `uid` = ? AND r.`type` = ? AND `objid` IN (?)',
231
-					[$this->user, $this->type, $chunk],
232
-					[null, null, IQueryBuilder::PARAM_INT_ARRAY]
233
-				);
234
-				while ($row = $result->fetch()) {
235
-					$objId = (int)$row['objid'];
236
-					if (!isset($entries[$objId])) {
237
-						$entries[$objId] = [];
238
-					}
239
-					$entries[$objId][] = $row['category'];
240
-				}
241
-				if ($result === null) {
242
-					\OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
243
-					return false;
244
-				}
245
-			}
246
-		} catch(\Exception $e) {
247
-			\OC::$server->getLogger()->logException($e, [
248
-				'message' => __METHOD__,
249
-				'level' => ILogger::ERROR,
250
-				'app' => 'core',
251
-			]);
252
-			return false;
253
-		}
254
-
255
-		return $entries;
256
-	}
257
-
258
-	/**
259
-	 * Get the a list if items tagged with $tag.
260
-	 *
261
-	 * Throws an exception if the tag could not be found.
262
-	 *
263
-	 * @param string $tag Tag id or name.
264
-	 * @return array|false An array of object ids or false on error.
265
-	 * @throws \Exception
266
-	 */
267
-	public function getIdsForTag($tag) {
268
-		$result = null;
269
-		$tagId = false;
270
-		if(is_numeric($tag)) {
271
-			$tagId = $tag;
272
-		} elseif(is_string($tag)) {
273
-			$tag = trim($tag);
274
-			if($tag === '') {
275
-				\OCP\Util::writeLog('core', __METHOD__.', Cannot use empty tag names', ILogger::DEBUG);
276
-				return false;
277
-			}
278
-			$tagId = $this->getTagId($tag);
279
-		}
280
-
281
-		if($tagId === false) {
282
-			$l10n = \OC::$server->getL10N('core');
283
-			throw new \Exception(
284
-				$l10n->t('Could not find category "%s"', [$tag])
285
-			);
286
-		}
287
-
288
-		$ids = [];
289
-		$sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE
290
-			. '` WHERE `categoryid` = ?';
291
-
292
-		try {
293
-			$stmt = \OC_DB::prepare($sql);
294
-			$result = $stmt->execute([$tagId]);
295
-			if ($result === null) {
296
-				\OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
297
-				return false;
298
-			}
299
-		} catch(\Exception $e) {
300
-			\OC::$server->getLogger()->logException($e, [
301
-				'message' => __METHOD__,
302
-				'level' => ILogger::ERROR,
303
-				'app' => 'core',
304
-			]);
305
-			return false;
306
-		}
307
-
308
-		if(!is_null($result)) {
309
-			while( $row = $result->fetchRow()) {
310
-				$id = (int)$row['objid'];
311
-
312
-				if ($this->includeShared) {
313
-					// We have to check if we are really allowed to access the
314
-					// items that are tagged with $tag. To that end, we ask the
315
-					// corresponding sharing backend if the item identified by $id
316
-					// is owned by any of $this->owners.
317
-					foreach ($this->owners as $owner) {
318
-						if ($this->backend->isValidSource($id, $owner)) {
319
-							$ids[] = $id;
320
-							break;
321
-						}
322
-					}
323
-				} else {
324
-					$ids[] = $id;
325
-				}
326
-			}
327
-		}
328
-
329
-		return $ids;
330
-	}
331
-
332
-	/**
333
-	 * Checks whether a tag is saved for the given user,
334
-	 * disregarding the ones shared with him or her.
335
-	 *
336
-	 * @param string $name The tag name to check for.
337
-	 * @param string $user The user whose tags are to be checked.
338
-	 * @return bool
339
-	 */
340
-	public function userHasTag($name, $user) {
341
-		$key = $this->array_searchi($name, $this->getTagsForUser($user));
342
-		return ($key !== false) ? $this->tags[$key]->getId() : false;
343
-	}
344
-
345
-	/**
346
-	 * Checks whether a tag is saved for or shared with the current user.
347
-	 *
348
-	 * @param string $name The tag name to check for.
349
-	 * @return bool
350
-	 */
351
-	public function hasTag($name) {
352
-		return $this->getTagId($name) !== false;
353
-	}
354
-
355
-	/**
356
-	 * Add a new tag.
357
-	 *
358
-	 * @param string $name A string with a name of the tag
359
-	 * @return false|int the id of the added tag or false on error.
360
-	 */
361
-	public function add($name) {
362
-		$name = trim($name);
363
-
364
-		if($name === '') {
365
-			\OCP\Util::writeLog('core', __METHOD__.', Cannot add an empty tag', ILogger::DEBUG);
366
-			return false;
367
-		}
368
-		if($this->userHasTag($name, $this->user)) {
369
-			\OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', ILogger::DEBUG);
370
-			return false;
371
-		}
372
-		try {
373
-			$tag = new Tag($this->user, $this->type, $name);
374
-			$tag = $this->mapper->insert($tag);
375
-			$this->tags[] = $tag;
376
-		} catch(\Exception $e) {
377
-			\OC::$server->getLogger()->logException($e, [
378
-				'message' => __METHOD__,
379
-				'level' => ILogger::ERROR,
380
-				'app' => 'core',
381
-			]);
382
-			return false;
383
-		}
384
-		\OCP\Util::writeLog('core', __METHOD__.', id: ' . $tag->getId(), ILogger::DEBUG);
385
-		return $tag->getId();
386
-	}
387
-
388
-	/**
389
-	 * Rename tag.
390
-	 *
391
-	 * @param string|integer $from The name or ID of the existing tag
392
-	 * @param string $to The new name of the tag.
393
-	 * @return bool
394
-	 */
395
-	public function rename($from, $to) {
396
-		$from = trim($from);
397
-		$to = trim($to);
398
-
399
-		if($to === '' || $from === '') {
400
-			\OCP\Util::writeLog('core', __METHOD__.', Cannot use empty tag names', ILogger::DEBUG);
401
-			return false;
402
-		}
403
-
404
-		if (is_numeric($from)) {
405
-			$key = $this->getTagById($from);
406
-		} else {
407
-			$key = $this->getTagByName($from);
408
-		}
409
-		if($key === false) {
410
-			\OCP\Util::writeLog('core', __METHOD__.', tag: ' . $from. ' does not exist', ILogger::DEBUG);
411
-			return false;
412
-		}
413
-		$tag = $this->tags[$key];
414
-
415
-		if($this->userHasTag($to, $tag->getOwner())) {
416
-			\OCP\Util::writeLog('core', __METHOD__.', A tag named ' . $to. ' already exists for user ' . $tag->getOwner() . '.', ILogger::DEBUG);
417
-			return false;
418
-		}
419
-
420
-		try {
421
-			$tag->setName($to);
422
-			$this->tags[$key] = $this->mapper->update($tag);
423
-		} catch(\Exception $e) {
424
-			\OC::$server->getLogger()->logException($e, [
425
-				'message' => __METHOD__,
426
-				'level' => ILogger::ERROR,
427
-				'app' => 'core',
428
-			]);
429
-			return false;
430
-		}
431
-		return true;
432
-	}
433
-
434
-	/**
435
-	 * Add a list of new tags.
436
-	 *
437
-	 * @param string[] $names A string with a name or an array of strings containing
438
-	 * the name(s) of the tag(s) to add.
439
-	 * @param bool $sync When true, save the tags
440
-	 * @param int|null $id int Optional object id to add to this|these tag(s)
441
-	 * @return bool Returns false on error.
442
-	 */
443
-	public function addMultiple($names, $sync=false, $id = null) {
444
-		if(!is_array($names)) {
445
-			$names = [$names];
446
-		}
447
-		$names = array_map('trim', $names);
448
-		array_filter($names);
449
-
450
-		$newones = [];
451
-		foreach($names as $name) {
452
-			if(!$this->hasTag($name) && $name !== '') {
453
-				$newones[] = new Tag($this->user, $this->type, $name);
454
-			}
455
-			if(!is_null($id) ) {
456
-				// Insert $objectid, $categoryid  pairs if not exist.
457
-				self::$relations[] = ['objid' => $id, 'tag' => $name];
458
-			}
459
-		}
460
-		$this->tags = array_merge($this->tags, $newones);
461
-		if($sync === true) {
462
-			$this->save();
463
-		}
464
-
465
-		return true;
466
-	}
467
-
468
-	/**
469
-	 * Save the list of tags and their object relations
470
-	 */
471
-	protected function save() {
472
-		if(is_array($this->tags)) {
473
-			foreach($this->tags as $tag) {
474
-				try {
475
-					if (!$this->mapper->tagExists($tag)) {
476
-						$this->mapper->insert($tag);
477
-					}
478
-				} catch(\Exception $e) {
479
-					\OC::$server->getLogger()->logException($e, [
480
-						'message' => __METHOD__,
481
-						'level' => ILogger::ERROR,
482
-						'app' => 'core',
483
-					]);
484
-				}
485
-			}
486
-
487
-			// reload tags to get the proper ids.
488
-			$this->tags = $this->mapper->loadTags($this->owners, $this->type);
489
-			\OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true),
490
-				ILogger::DEBUG);
491
-			// Loop through temporarily cached objectid/tagname pairs
492
-			// and save relations.
493
-			$tags = $this->tags;
494
-			// For some reason this is needed or array_search(i) will return 0..?
495
-			ksort($tags);
496
-			$dbConnection = \OC::$server->getDatabaseConnection();
497
-			foreach(self::$relations as $relation) {
498
-				$tagId = $this->getTagId($relation['tag']);
499
-				\OCP\Util::writeLog('core', __METHOD__ . 'catid, ' . $relation['tag'] . ' ' . $tagId, ILogger::DEBUG);
500
-				if($tagId) {
501
-					try {
502
-						$dbConnection->insertIfNotExist(self::RELATION_TABLE,
503
-							[
504
-								'objid' => $relation['objid'],
505
-								'categoryid' => $tagId,
506
-								'type' => $this->type,
507
-							]);
508
-					} catch(\Exception $e) {
509
-						\OC::$server->getLogger()->logException($e, [
510
-							'message' => __METHOD__,
511
-							'level' => ILogger::ERROR,
512
-							'app' => 'core',
513
-						]);
514
-					}
515
-				}
516
-			}
517
-			self::$relations = []; // reset
518
-		} else {
519
-			\OCP\Util::writeLog('core', __METHOD__.', $this->tags is not an array! '
520
-				. print_r($this->tags, true), ILogger::ERROR);
521
-		}
522
-	}
523
-
524
-	/**
525
-	 * Delete tags and tag/object relations for a user.
526
-	 *
527
-	 * For hooking up on post_deleteUser
528
-	 *
529
-	 * @param array $arguments
530
-	 */
531
-	public static function post_deleteUser($arguments) {
532
-		// Find all objectid/tagId pairs.
533
-		$result = null;
534
-		try {
535
-			$stmt = \OC_DB::prepare('SELECT `id` FROM `' . self::TAG_TABLE . '` '
536
-				. 'WHERE `uid` = ?');
537
-			$result = $stmt->execute([$arguments['uid']]);
538
-			if ($result === null) {
539
-				\OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
540
-			}
541
-		} catch(\Exception $e) {
542
-			\OC::$server->getLogger()->logException($e, [
543
-				'message' => __METHOD__,
544
-				'level' => ILogger::ERROR,
545
-				'app' => 'core',
546
-			]);
547
-		}
548
-
549
-		if(!is_null($result)) {
550
-			try {
551
-				$stmt = \OC_DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` '
552
-					. 'WHERE `categoryid` = ?');
553
-				while( $row = $result->fetchRow()) {
554
-					try {
555
-						$stmt->execute([$row['id']]);
556
-					} catch(\Exception $e) {
557
-						\OC::$server->getLogger()->logException($e, [
558
-							'message' => __METHOD__,
559
-							'level' => ILogger::ERROR,
560
-							'app' => 'core',
561
-						]);
562
-					}
563
-				}
564
-			} catch(\Exception $e) {
565
-				\OC::$server->getLogger()->logException($e, [
566
-					'message' => __METHOD__,
567
-					'level' => ILogger::ERROR,
568
-					'app' => 'core',
569
-				]);
570
-			}
571
-		}
572
-		try {
573
-			$stmt = \OC_DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` '
574
-				. 'WHERE `uid` = ?');
575
-			$result = $stmt->execute([$arguments['uid']]);
576
-			if ($result === null) {
577
-				\OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
578
-			}
579
-		} catch(\Exception $e) {
580
-			\OC::$server->getLogger()->logException($e, [
581
-				'message' => __METHOD__,
582
-				'level' => ILogger::ERROR,
583
-				'app' => 'core',
584
-			]);
585
-		}
586
-	}
587
-
588
-	/**
589
-	 * Delete tag/object relations from the db
590
-	 *
591
-	 * @param array $ids The ids of the objects
592
-	 * @return boolean Returns false on error.
593
-	 */
594
-	public function purgeObjects(array $ids) {
595
-		if(count($ids) === 0) {
596
-			// job done ;)
597
-			return true;
598
-		}
599
-		$updates = $ids;
600
-		try {
601
-			$query = 'DELETE FROM `' . self::RELATION_TABLE . '` ';
602
-			$query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids)-1) . '?) ';
603
-			$query .= 'AND `type`= ?';
604
-			$updates[] = $this->type;
605
-			$stmt = \OC_DB::prepare($query);
606
-			$result = $stmt->execute($updates);
607
-			if ($result === null) {
608
-				\OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
609
-				return false;
610
-			}
611
-		} catch(\Exception $e) {
612
-			\OC::$server->getLogger()->logException($e, [
613
-				'message' => __METHOD__,
614
-				'level' => ILogger::ERROR,
615
-				'app' => 'core',
616
-			]);
617
-			return false;
618
-		}
619
-		return true;
620
-	}
621
-
622
-	/**
623
-	 * Get favorites for an object type
624
-	 *
625
-	 * @return array|false An array of object ids.
626
-	 */
627
-	public function getFavorites() {
628
-		if(!$this->userHasTag(ITags::TAG_FAVORITE, $this->user)) {
629
-			return [];
630
-		}
631
-
632
-		try {
633
-			return $this->getIdsForTag(ITags::TAG_FAVORITE);
634
-		} catch(\Exception $e) {
635
-			\OC::$server->getLogger()->logException($e, [
636
-				'message' => __METHOD__,
637
-				'level' => ILogger::ERROR,
638
-				'app' => 'core',
639
-			]);
640
-			return [];
641
-		}
642
-	}
643
-
644
-	/**
645
-	 * Add an object to favorites
646
-	 *
647
-	 * @param int $objid The id of the object
648
-	 * @return boolean
649
-	 */
650
-	public function addToFavorites($objid) {
651
-		if(!$this->userHasTag(ITags::TAG_FAVORITE, $this->user)) {
652
-			$this->add(ITags::TAG_FAVORITE);
653
-		}
654
-		return $this->tagAs($objid, ITags::TAG_FAVORITE);
655
-	}
656
-
657
-	/**
658
-	 * Remove an object from favorites
659
-	 *
660
-	 * @param int $objid The id of the object
661
-	 * @return boolean
662
-	 */
663
-	public function removeFromFavorites($objid) {
664
-		return $this->unTag($objid, ITags::TAG_FAVORITE);
665
-	}
666
-
667
-	/**
668
-	 * Creates a tag/object relation.
669
-	 *
670
-	 * @param int $objid The id of the object
671
-	 * @param string $tag The id or name of the tag
672
-	 * @return boolean Returns false on error.
673
-	 */
674
-	public function tagAs($objid, $tag) {
675
-		if(is_string($tag) && !is_numeric($tag)) {
676
-			$tag = trim($tag);
677
-			if($tag === '') {
678
-				\OCP\Util::writeLog('core', __METHOD__.', Cannot add an empty tag', ILogger::DEBUG);
679
-				return false;
680
-			}
681
-			if(!$this->hasTag($tag)) {
682
-				$this->add($tag);
683
-			}
684
-			$tagId =  $this->getTagId($tag);
685
-		} else {
686
-			$tagId = $tag;
687
-		}
688
-		try {
689
-			\OC::$server->getDatabaseConnection()->insertIfNotExist(self::RELATION_TABLE,
690
-				[
691
-					'objid' => $objid,
692
-					'categoryid' => $tagId,
693
-					'type' => $this->type,
694
-				]);
695
-		} catch(\Exception $e) {
696
-			\OC::$server->getLogger()->logException($e, [
697
-				'message' => __METHOD__,
698
-				'level' => ILogger::ERROR,
699
-				'app' => 'core',
700
-			]);
701
-			return false;
702
-		}
703
-		return true;
704
-	}
705
-
706
-	/**
707
-	 * Delete single tag/object relation from the db
708
-	 *
709
-	 * @param int $objid The id of the object
710
-	 * @param string $tag The id or name of the tag
711
-	 * @return boolean
712
-	 */
713
-	public function unTag($objid, $tag) {
714
-		if(is_string($tag) && !is_numeric($tag)) {
715
-			$tag = trim($tag);
716
-			if($tag === '') {
717
-				\OCP\Util::writeLog('core', __METHOD__.', Tag name is empty', ILogger::DEBUG);
718
-				return false;
719
-			}
720
-			$tagId =  $this->getTagId($tag);
721
-		} else {
722
-			$tagId = $tag;
723
-		}
724
-
725
-		try {
726
-			$sql = 'DELETE FROM `' . self::RELATION_TABLE . '` '
727
-					. 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?';
728
-			$stmt = \OC_DB::prepare($sql);
729
-			$stmt->execute([$objid, $tagId, $this->type]);
730
-		} catch(\Exception $e) {
731
-			\OC::$server->getLogger()->logException($e, [
732
-				'message' => __METHOD__,
733
-				'level' => ILogger::ERROR,
734
-				'app' => 'core',
735
-			]);
736
-			return false;
737
-		}
738
-		return true;
739
-	}
740
-
741
-	/**
742
-	 * Delete tags from the database.
743
-	 *
744
-	 * @param string[]|integer[] $names An array of tags (names or IDs) to delete
745
-	 * @return bool Returns false on error
746
-	 */
747
-	public function delete($names) {
748
-		if(!is_array($names)) {
749
-			$names = [$names];
750
-		}
751
-
752
-		$names = array_map('trim', $names);
753
-		array_filter($names);
754
-
755
-		\OCP\Util::writeLog('core', __METHOD__ . ', before: '
756
-			. print_r($this->tags, true), ILogger::DEBUG);
757
-		foreach($names as $name) {
758
-			$id = null;
759
-
760
-			if (is_numeric($name)) {
761
-				$key = $this->getTagById($name);
762
-			} else {
763
-				$key = $this->getTagByName($name);
764
-			}
765
-			if ($key !== false) {
766
-				$tag = $this->tags[$key];
767
-				$id = $tag->getId();
768
-				unset($this->tags[$key]);
769
-				$this->mapper->delete($tag);
770
-			} else {
771
-				\OCP\Util::writeLog('core', __METHOD__ . 'Cannot delete tag ' . $name
772
-					. ': not found.', ILogger::ERROR);
773
-			}
774
-			if(!is_null($id) && $id !== false) {
775
-				try {
776
-					$sql = 'DELETE FROM `' . self::RELATION_TABLE . '` '
777
-							. 'WHERE `categoryid` = ?';
778
-					$stmt = \OC_DB::prepare($sql);
779
-					$result = $stmt->execute([$id]);
780
-					if ($result === null) {
781
-						\OCP\Util::writeLog('core',
782
-							__METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(),
783
-							ILogger::ERROR);
784
-						return false;
785
-					}
786
-				} catch(\Exception $e) {
787
-					\OC::$server->getLogger()->logException($e, [
788
-						'message' => __METHOD__,
789
-						'level' => ILogger::ERROR,
790
-						'app' => 'core',
791
-					]);
792
-					return false;
793
-				}
794
-			}
795
-		}
796
-		return true;
797
-	}
798
-
799
-	// case-insensitive array_search
800
-	protected function array_searchi($needle, $haystack, $mem='getName') {
801
-		if(!is_array($haystack)) {
802
-			return false;
803
-		}
804
-		return array_search(strtolower($needle), array_map(
805
-			function ($tag) use ($mem) {
806
-				return strtolower(call_user_func([$tag, $mem]));
807
-			}, $haystack)
808
-		);
809
-	}
810
-
811
-	/**
812
-	 * Get a tag's ID.
813
-	 *
814
-	 * @param string $name The tag name to look for.
815
-	 * @return string|bool The tag's id or false if no matching tag is found.
816
-	 */
817
-	private function getTagId($name) {
818
-		$key = $this->array_searchi($name, $this->tags);
819
-		if ($key !== false) {
820
-			return $this->tags[$key]->getId();
821
-		}
822
-		return false;
823
-	}
824
-
825
-	/**
826
-	 * Get a tag by its name.
827
-	 *
828
-	 * @param string $name The tag name.
829
-	 * @return integer|bool The tag object's offset within the $this->tags
830
-	 *                      array or false if it doesn't exist.
831
-	 */
832
-	private function getTagByName($name) {
833
-		return $this->array_searchi($name, $this->tags, 'getName');
834
-	}
835
-
836
-	/**
837
-	 * Get a tag by its ID.
838
-	 *
839
-	 * @param string $id The tag ID to look for.
840
-	 * @return integer|bool The tag object's offset within the $this->tags
841
-	 *                      array or false if it doesn't exist.
842
-	 */
843
-	private function getTagById($id) {
844
-		return $this->array_searchi($id, $this->tags, 'getId');
845
-	}
846
-
847
-	/**
848
-	 * Returns an array mapping a given tag's properties to its values:
849
-	 * ['id' => 0, 'name' = 'Tag', 'owner' = 'User', 'type' => 'tagtype']
850
-	 *
851
-	 * @param Tag $tag The tag that is going to be mapped
852
-	 * @return array
853
-	 */
854
-	private function tagMap(Tag $tag) {
855
-		return [
856
-			'id'    => $tag->getId(),
857
-			'name'  => $tag->getName(),
858
-			'owner' => $tag->getOwner(),
859
-			'type'  => $tag->getType()
860
-		];
861
-	}
57
+    /**
58
+     * Tags
59
+     *
60
+     * @var array
61
+     */
62
+    private $tags = [];
63
+
64
+    /**
65
+     * Used for storing objectid/categoryname pairs while rescanning.
66
+     *
67
+     * @var array
68
+     */
69
+    private static $relations = [];
70
+
71
+    /**
72
+     * Type
73
+     *
74
+     * @var string
75
+     */
76
+    private $type;
77
+
78
+    /**
79
+     * User
80
+     *
81
+     * @var string
82
+     */
83
+    private $user;
84
+
85
+    /**
86
+     * Are we including tags for shared items?
87
+     *
88
+     * @var bool
89
+     */
90
+    private $includeShared = false;
91
+
92
+    /**
93
+     * The current user, plus any owners of the items shared with the current
94
+     * user, if $this->includeShared === true.
95
+     *
96
+     * @var array
97
+     */
98
+    private $owners = [];
99
+
100
+    /**
101
+     * The Mapper we're using to communicate our Tag objects to the database.
102
+     *
103
+     * @var TagMapper
104
+     */
105
+    private $mapper;
106
+
107
+    /**
108
+     * The sharing backend for objects of $this->type. Required if
109
+     * $this->includeShared === true to determine ownership of items.
110
+     *
111
+     * @var \OCP\Share_Backend
112
+     */
113
+    private $backend;
114
+
115
+    const TAG_TABLE = '*PREFIX*vcategory';
116
+    const RELATION_TABLE = '*PREFIX*vcategory_to_object';
117
+
118
+    /**
119
+     * Constructor.
120
+     *
121
+     * @param TagMapper $mapper Instance of the TagMapper abstraction layer.
122
+     * @param string $user The user whose data the object will operate on.
123
+     * @param string $type The type of items for which tags will be loaded.
124
+     * @param array $defaultTags Tags that should be created at construction.
125
+     * @param boolean $includeShared Whether to include tags for items shared with this user by others.
126
+     */
127
+    public function __construct(TagMapper $mapper, $user, $type, $defaultTags = [], $includeShared = false) {
128
+        $this->mapper = $mapper;
129
+        $this->user = $user;
130
+        $this->type = $type;
131
+        $this->includeShared = $includeShared;
132
+        $this->owners = [$this->user];
133
+        if ($this->includeShared) {
134
+            $this->owners = array_merge($this->owners, \OC\Share\Share::getSharedItemsOwners($this->user, $this->type, true));
135
+            $this->backend = \OC\Share\Share::getBackend($this->type);
136
+        }
137
+        $this->tags = $this->mapper->loadTags($this->owners, $this->type);
138
+
139
+        if(count($defaultTags) > 0 && count($this->tags) === 0) {
140
+            $this->addMultiple($defaultTags, true);
141
+        }
142
+    }
143
+
144
+    /**
145
+     * Check if any tags are saved for this type and user.
146
+     *
147
+     * @return boolean
148
+     */
149
+    public function isEmpty() {
150
+        return count($this->tags) === 0;
151
+    }
152
+
153
+    /**
154
+     * Returns an array mapping a given tag's properties to its values:
155
+     * ['id' => 0, 'name' = 'Tag', 'owner' = 'User', 'type' => 'tagtype']
156
+     *
157
+     * @param string $id The ID of the tag that is going to be mapped
158
+     * @return array|false
159
+     */
160
+    public function getTag($id) {
161
+        $key = $this->getTagById($id);
162
+        if ($key !== false) {
163
+            return $this->tagMap($this->tags[$key]);
164
+        }
165
+        return false;
166
+    }
167
+
168
+    /**
169
+     * Get the tags for a specific user.
170
+     *
171
+     * This returns an array with maps containing each tag's properties:
172
+     * [
173
+     * 	['id' => 0, 'name' = 'First tag', 'owner' = 'User', 'type' => 'tagtype'],
174
+     * 	['id' => 1, 'name' = 'Shared tag', 'owner' = 'Other user', 'type' => 'tagtype'],
175
+     * ]
176
+     *
177
+     * @return array
178
+     */
179
+    public function getTags() {
180
+        if(!count($this->tags)) {
181
+            return [];
182
+        }
183
+
184
+        usort($this->tags, function ($a, $b) {
185
+            return strnatcasecmp($a->getName(), $b->getName());
186
+        });
187
+        $tagMap = [];
188
+
189
+        foreach($this->tags as $tag) {
190
+            if($tag->getName() !== ITags::TAG_FAVORITE) {
191
+                $tagMap[] = $this->tagMap($tag);
192
+            }
193
+        }
194
+        return $tagMap;
195
+
196
+    }
197
+
198
+    /**
199
+     * Return only the tags owned by the given user, omitting any tags shared
200
+     * by other users.
201
+     *
202
+     * @param string $user The user whose tags are to be checked.
203
+     * @return array An array of Tag objects.
204
+     */
205
+    public function getTagsForUser($user) {
206
+        return array_filter($this->tags,
207
+            function ($tag) use ($user) {
208
+                return $tag->getOwner() === $user;
209
+            }
210
+        );
211
+    }
212
+
213
+    /**
214
+     * Get the list of tags for the given ids.
215
+     *
216
+     * @param array $objIds array of object ids
217
+     * @return array|boolean of tags id as key to array of tag names
218
+     * or false if an error occurred
219
+     */
220
+    public function getTagsForObjects(array $objIds) {
221
+        $entries = [];
222
+
223
+        try {
224
+            $conn = \OC::$server->getDatabaseConnection();
225
+            $chunks = array_chunk($objIds, 900, false);
226
+            foreach ($chunks as $chunk) {
227
+                $result = $conn->executeQuery(
228
+                    'SELECT `category`, `categoryid`, `objid` ' .
229
+                    'FROM `' . self::RELATION_TABLE . '` r, `' . self::TAG_TABLE . '` ' .
230
+                    'WHERE `categoryid` = `id` AND `uid` = ? AND r.`type` = ? AND `objid` IN (?)',
231
+                    [$this->user, $this->type, $chunk],
232
+                    [null, null, IQueryBuilder::PARAM_INT_ARRAY]
233
+                );
234
+                while ($row = $result->fetch()) {
235
+                    $objId = (int)$row['objid'];
236
+                    if (!isset($entries[$objId])) {
237
+                        $entries[$objId] = [];
238
+                    }
239
+                    $entries[$objId][] = $row['category'];
240
+                }
241
+                if ($result === null) {
242
+                    \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
243
+                    return false;
244
+                }
245
+            }
246
+        } catch(\Exception $e) {
247
+            \OC::$server->getLogger()->logException($e, [
248
+                'message' => __METHOD__,
249
+                'level' => ILogger::ERROR,
250
+                'app' => 'core',
251
+            ]);
252
+            return false;
253
+        }
254
+
255
+        return $entries;
256
+    }
257
+
258
+    /**
259
+     * Get the a list if items tagged with $tag.
260
+     *
261
+     * Throws an exception if the tag could not be found.
262
+     *
263
+     * @param string $tag Tag id or name.
264
+     * @return array|false An array of object ids or false on error.
265
+     * @throws \Exception
266
+     */
267
+    public function getIdsForTag($tag) {
268
+        $result = null;
269
+        $tagId = false;
270
+        if(is_numeric($tag)) {
271
+            $tagId = $tag;
272
+        } elseif(is_string($tag)) {
273
+            $tag = trim($tag);
274
+            if($tag === '') {
275
+                \OCP\Util::writeLog('core', __METHOD__.', Cannot use empty tag names', ILogger::DEBUG);
276
+                return false;
277
+            }
278
+            $tagId = $this->getTagId($tag);
279
+        }
280
+
281
+        if($tagId === false) {
282
+            $l10n = \OC::$server->getL10N('core');
283
+            throw new \Exception(
284
+                $l10n->t('Could not find category "%s"', [$tag])
285
+            );
286
+        }
287
+
288
+        $ids = [];
289
+        $sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE
290
+            . '` WHERE `categoryid` = ?';
291
+
292
+        try {
293
+            $stmt = \OC_DB::prepare($sql);
294
+            $result = $stmt->execute([$tagId]);
295
+            if ($result === null) {
296
+                \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
297
+                return false;
298
+            }
299
+        } catch(\Exception $e) {
300
+            \OC::$server->getLogger()->logException($e, [
301
+                'message' => __METHOD__,
302
+                'level' => ILogger::ERROR,
303
+                'app' => 'core',
304
+            ]);
305
+            return false;
306
+        }
307
+
308
+        if(!is_null($result)) {
309
+            while( $row = $result->fetchRow()) {
310
+                $id = (int)$row['objid'];
311
+
312
+                if ($this->includeShared) {
313
+                    // We have to check if we are really allowed to access the
314
+                    // items that are tagged with $tag. To that end, we ask the
315
+                    // corresponding sharing backend if the item identified by $id
316
+                    // is owned by any of $this->owners.
317
+                    foreach ($this->owners as $owner) {
318
+                        if ($this->backend->isValidSource($id, $owner)) {
319
+                            $ids[] = $id;
320
+                            break;
321
+                        }
322
+                    }
323
+                } else {
324
+                    $ids[] = $id;
325
+                }
326
+            }
327
+        }
328
+
329
+        return $ids;
330
+    }
331
+
332
+    /**
333
+     * Checks whether a tag is saved for the given user,
334
+     * disregarding the ones shared with him or her.
335
+     *
336
+     * @param string $name The tag name to check for.
337
+     * @param string $user The user whose tags are to be checked.
338
+     * @return bool
339
+     */
340
+    public function userHasTag($name, $user) {
341
+        $key = $this->array_searchi($name, $this->getTagsForUser($user));
342
+        return ($key !== false) ? $this->tags[$key]->getId() : false;
343
+    }
344
+
345
+    /**
346
+     * Checks whether a tag is saved for or shared with the current user.
347
+     *
348
+     * @param string $name The tag name to check for.
349
+     * @return bool
350
+     */
351
+    public function hasTag($name) {
352
+        return $this->getTagId($name) !== false;
353
+    }
354
+
355
+    /**
356
+     * Add a new tag.
357
+     *
358
+     * @param string $name A string with a name of the tag
359
+     * @return false|int the id of the added tag or false on error.
360
+     */
361
+    public function add($name) {
362
+        $name = trim($name);
363
+
364
+        if($name === '') {
365
+            \OCP\Util::writeLog('core', __METHOD__.', Cannot add an empty tag', ILogger::DEBUG);
366
+            return false;
367
+        }
368
+        if($this->userHasTag($name, $this->user)) {
369
+            \OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', ILogger::DEBUG);
370
+            return false;
371
+        }
372
+        try {
373
+            $tag = new Tag($this->user, $this->type, $name);
374
+            $tag = $this->mapper->insert($tag);
375
+            $this->tags[] = $tag;
376
+        } catch(\Exception $e) {
377
+            \OC::$server->getLogger()->logException($e, [
378
+                'message' => __METHOD__,
379
+                'level' => ILogger::ERROR,
380
+                'app' => 'core',
381
+            ]);
382
+            return false;
383
+        }
384
+        \OCP\Util::writeLog('core', __METHOD__.', id: ' . $tag->getId(), ILogger::DEBUG);
385
+        return $tag->getId();
386
+    }
387
+
388
+    /**
389
+     * Rename tag.
390
+     *
391
+     * @param string|integer $from The name or ID of the existing tag
392
+     * @param string $to The new name of the tag.
393
+     * @return bool
394
+     */
395
+    public function rename($from, $to) {
396
+        $from = trim($from);
397
+        $to = trim($to);
398
+
399
+        if($to === '' || $from === '') {
400
+            \OCP\Util::writeLog('core', __METHOD__.', Cannot use empty tag names', ILogger::DEBUG);
401
+            return false;
402
+        }
403
+
404
+        if (is_numeric($from)) {
405
+            $key = $this->getTagById($from);
406
+        } else {
407
+            $key = $this->getTagByName($from);
408
+        }
409
+        if($key === false) {
410
+            \OCP\Util::writeLog('core', __METHOD__.', tag: ' . $from. ' does not exist', ILogger::DEBUG);
411
+            return false;
412
+        }
413
+        $tag = $this->tags[$key];
414
+
415
+        if($this->userHasTag($to, $tag->getOwner())) {
416
+            \OCP\Util::writeLog('core', __METHOD__.', A tag named ' . $to. ' already exists for user ' . $tag->getOwner() . '.', ILogger::DEBUG);
417
+            return false;
418
+        }
419
+
420
+        try {
421
+            $tag->setName($to);
422
+            $this->tags[$key] = $this->mapper->update($tag);
423
+        } catch(\Exception $e) {
424
+            \OC::$server->getLogger()->logException($e, [
425
+                'message' => __METHOD__,
426
+                'level' => ILogger::ERROR,
427
+                'app' => 'core',
428
+            ]);
429
+            return false;
430
+        }
431
+        return true;
432
+    }
433
+
434
+    /**
435
+     * Add a list of new tags.
436
+     *
437
+     * @param string[] $names A string with a name or an array of strings containing
438
+     * the name(s) of the tag(s) to add.
439
+     * @param bool $sync When true, save the tags
440
+     * @param int|null $id int Optional object id to add to this|these tag(s)
441
+     * @return bool Returns false on error.
442
+     */
443
+    public function addMultiple($names, $sync=false, $id = null) {
444
+        if(!is_array($names)) {
445
+            $names = [$names];
446
+        }
447
+        $names = array_map('trim', $names);
448
+        array_filter($names);
449
+
450
+        $newones = [];
451
+        foreach($names as $name) {
452
+            if(!$this->hasTag($name) && $name !== '') {
453
+                $newones[] = new Tag($this->user, $this->type, $name);
454
+            }
455
+            if(!is_null($id) ) {
456
+                // Insert $objectid, $categoryid  pairs if not exist.
457
+                self::$relations[] = ['objid' => $id, 'tag' => $name];
458
+            }
459
+        }
460
+        $this->tags = array_merge($this->tags, $newones);
461
+        if($sync === true) {
462
+            $this->save();
463
+        }
464
+
465
+        return true;
466
+    }
467
+
468
+    /**
469
+     * Save the list of tags and their object relations
470
+     */
471
+    protected function save() {
472
+        if(is_array($this->tags)) {
473
+            foreach($this->tags as $tag) {
474
+                try {
475
+                    if (!$this->mapper->tagExists($tag)) {
476
+                        $this->mapper->insert($tag);
477
+                    }
478
+                } catch(\Exception $e) {
479
+                    \OC::$server->getLogger()->logException($e, [
480
+                        'message' => __METHOD__,
481
+                        'level' => ILogger::ERROR,
482
+                        'app' => 'core',
483
+                    ]);
484
+                }
485
+            }
486
+
487
+            // reload tags to get the proper ids.
488
+            $this->tags = $this->mapper->loadTags($this->owners, $this->type);
489
+            \OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true),
490
+                ILogger::DEBUG);
491
+            // Loop through temporarily cached objectid/tagname pairs
492
+            // and save relations.
493
+            $tags = $this->tags;
494
+            // For some reason this is needed or array_search(i) will return 0..?
495
+            ksort($tags);
496
+            $dbConnection = \OC::$server->getDatabaseConnection();
497
+            foreach(self::$relations as $relation) {
498
+                $tagId = $this->getTagId($relation['tag']);
499
+                \OCP\Util::writeLog('core', __METHOD__ . 'catid, ' . $relation['tag'] . ' ' . $tagId, ILogger::DEBUG);
500
+                if($tagId) {
501
+                    try {
502
+                        $dbConnection->insertIfNotExist(self::RELATION_TABLE,
503
+                            [
504
+                                'objid' => $relation['objid'],
505
+                                'categoryid' => $tagId,
506
+                                'type' => $this->type,
507
+                            ]);
508
+                    } catch(\Exception $e) {
509
+                        \OC::$server->getLogger()->logException($e, [
510
+                            'message' => __METHOD__,
511
+                            'level' => ILogger::ERROR,
512
+                            'app' => 'core',
513
+                        ]);
514
+                    }
515
+                }
516
+            }
517
+            self::$relations = []; // reset
518
+        } else {
519
+            \OCP\Util::writeLog('core', __METHOD__.', $this->tags is not an array! '
520
+                . print_r($this->tags, true), ILogger::ERROR);
521
+        }
522
+    }
523
+
524
+    /**
525
+     * Delete tags and tag/object relations for a user.
526
+     *
527
+     * For hooking up on post_deleteUser
528
+     *
529
+     * @param array $arguments
530
+     */
531
+    public static function post_deleteUser($arguments) {
532
+        // Find all objectid/tagId pairs.
533
+        $result = null;
534
+        try {
535
+            $stmt = \OC_DB::prepare('SELECT `id` FROM `' . self::TAG_TABLE . '` '
536
+                . 'WHERE `uid` = ?');
537
+            $result = $stmt->execute([$arguments['uid']]);
538
+            if ($result === null) {
539
+                \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
540
+            }
541
+        } catch(\Exception $e) {
542
+            \OC::$server->getLogger()->logException($e, [
543
+                'message' => __METHOD__,
544
+                'level' => ILogger::ERROR,
545
+                'app' => 'core',
546
+            ]);
547
+        }
548
+
549
+        if(!is_null($result)) {
550
+            try {
551
+                $stmt = \OC_DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` '
552
+                    . 'WHERE `categoryid` = ?');
553
+                while( $row = $result->fetchRow()) {
554
+                    try {
555
+                        $stmt->execute([$row['id']]);
556
+                    } catch(\Exception $e) {
557
+                        \OC::$server->getLogger()->logException($e, [
558
+                            'message' => __METHOD__,
559
+                            'level' => ILogger::ERROR,
560
+                            'app' => 'core',
561
+                        ]);
562
+                    }
563
+                }
564
+            } catch(\Exception $e) {
565
+                \OC::$server->getLogger()->logException($e, [
566
+                    'message' => __METHOD__,
567
+                    'level' => ILogger::ERROR,
568
+                    'app' => 'core',
569
+                ]);
570
+            }
571
+        }
572
+        try {
573
+            $stmt = \OC_DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` '
574
+                . 'WHERE `uid` = ?');
575
+            $result = $stmt->execute([$arguments['uid']]);
576
+            if ($result === null) {
577
+                \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
578
+            }
579
+        } catch(\Exception $e) {
580
+            \OC::$server->getLogger()->logException($e, [
581
+                'message' => __METHOD__,
582
+                'level' => ILogger::ERROR,
583
+                'app' => 'core',
584
+            ]);
585
+        }
586
+    }
587
+
588
+    /**
589
+     * Delete tag/object relations from the db
590
+     *
591
+     * @param array $ids The ids of the objects
592
+     * @return boolean Returns false on error.
593
+     */
594
+    public function purgeObjects(array $ids) {
595
+        if(count($ids) === 0) {
596
+            // job done ;)
597
+            return true;
598
+        }
599
+        $updates = $ids;
600
+        try {
601
+            $query = 'DELETE FROM `' . self::RELATION_TABLE . '` ';
602
+            $query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids)-1) . '?) ';
603
+            $query .= 'AND `type`= ?';
604
+            $updates[] = $this->type;
605
+            $stmt = \OC_DB::prepare($query);
606
+            $result = $stmt->execute($updates);
607
+            if ($result === null) {
608
+                \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
609
+                return false;
610
+            }
611
+        } catch(\Exception $e) {
612
+            \OC::$server->getLogger()->logException($e, [
613
+                'message' => __METHOD__,
614
+                'level' => ILogger::ERROR,
615
+                'app' => 'core',
616
+            ]);
617
+            return false;
618
+        }
619
+        return true;
620
+    }
621
+
622
+    /**
623
+     * Get favorites for an object type
624
+     *
625
+     * @return array|false An array of object ids.
626
+     */
627
+    public function getFavorites() {
628
+        if(!$this->userHasTag(ITags::TAG_FAVORITE, $this->user)) {
629
+            return [];
630
+        }
631
+
632
+        try {
633
+            return $this->getIdsForTag(ITags::TAG_FAVORITE);
634
+        } catch(\Exception $e) {
635
+            \OC::$server->getLogger()->logException($e, [
636
+                'message' => __METHOD__,
637
+                'level' => ILogger::ERROR,
638
+                'app' => 'core',
639
+            ]);
640
+            return [];
641
+        }
642
+    }
643
+
644
+    /**
645
+     * Add an object to favorites
646
+     *
647
+     * @param int $objid The id of the object
648
+     * @return boolean
649
+     */
650
+    public function addToFavorites($objid) {
651
+        if(!$this->userHasTag(ITags::TAG_FAVORITE, $this->user)) {
652
+            $this->add(ITags::TAG_FAVORITE);
653
+        }
654
+        return $this->tagAs($objid, ITags::TAG_FAVORITE);
655
+    }
656
+
657
+    /**
658
+     * Remove an object from favorites
659
+     *
660
+     * @param int $objid The id of the object
661
+     * @return boolean
662
+     */
663
+    public function removeFromFavorites($objid) {
664
+        return $this->unTag($objid, ITags::TAG_FAVORITE);
665
+    }
666
+
667
+    /**
668
+     * Creates a tag/object relation.
669
+     *
670
+     * @param int $objid The id of the object
671
+     * @param string $tag The id or name of the tag
672
+     * @return boolean Returns false on error.
673
+     */
674
+    public function tagAs($objid, $tag) {
675
+        if(is_string($tag) && !is_numeric($tag)) {
676
+            $tag = trim($tag);
677
+            if($tag === '') {
678
+                \OCP\Util::writeLog('core', __METHOD__.', Cannot add an empty tag', ILogger::DEBUG);
679
+                return false;
680
+            }
681
+            if(!$this->hasTag($tag)) {
682
+                $this->add($tag);
683
+            }
684
+            $tagId =  $this->getTagId($tag);
685
+        } else {
686
+            $tagId = $tag;
687
+        }
688
+        try {
689
+            \OC::$server->getDatabaseConnection()->insertIfNotExist(self::RELATION_TABLE,
690
+                [
691
+                    'objid' => $objid,
692
+                    'categoryid' => $tagId,
693
+                    'type' => $this->type,
694
+                ]);
695
+        } catch(\Exception $e) {
696
+            \OC::$server->getLogger()->logException($e, [
697
+                'message' => __METHOD__,
698
+                'level' => ILogger::ERROR,
699
+                'app' => 'core',
700
+            ]);
701
+            return false;
702
+        }
703
+        return true;
704
+    }
705
+
706
+    /**
707
+     * Delete single tag/object relation from the db
708
+     *
709
+     * @param int $objid The id of the object
710
+     * @param string $tag The id or name of the tag
711
+     * @return boolean
712
+     */
713
+    public function unTag($objid, $tag) {
714
+        if(is_string($tag) && !is_numeric($tag)) {
715
+            $tag = trim($tag);
716
+            if($tag === '') {
717
+                \OCP\Util::writeLog('core', __METHOD__.', Tag name is empty', ILogger::DEBUG);
718
+                return false;
719
+            }
720
+            $tagId =  $this->getTagId($tag);
721
+        } else {
722
+            $tagId = $tag;
723
+        }
724
+
725
+        try {
726
+            $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` '
727
+                    . 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?';
728
+            $stmt = \OC_DB::prepare($sql);
729
+            $stmt->execute([$objid, $tagId, $this->type]);
730
+        } catch(\Exception $e) {
731
+            \OC::$server->getLogger()->logException($e, [
732
+                'message' => __METHOD__,
733
+                'level' => ILogger::ERROR,
734
+                'app' => 'core',
735
+            ]);
736
+            return false;
737
+        }
738
+        return true;
739
+    }
740
+
741
+    /**
742
+     * Delete tags from the database.
743
+     *
744
+     * @param string[]|integer[] $names An array of tags (names or IDs) to delete
745
+     * @return bool Returns false on error
746
+     */
747
+    public function delete($names) {
748
+        if(!is_array($names)) {
749
+            $names = [$names];
750
+        }
751
+
752
+        $names = array_map('trim', $names);
753
+        array_filter($names);
754
+
755
+        \OCP\Util::writeLog('core', __METHOD__ . ', before: '
756
+            . print_r($this->tags, true), ILogger::DEBUG);
757
+        foreach($names as $name) {
758
+            $id = null;
759
+
760
+            if (is_numeric($name)) {
761
+                $key = $this->getTagById($name);
762
+            } else {
763
+                $key = $this->getTagByName($name);
764
+            }
765
+            if ($key !== false) {
766
+                $tag = $this->tags[$key];
767
+                $id = $tag->getId();
768
+                unset($this->tags[$key]);
769
+                $this->mapper->delete($tag);
770
+            } else {
771
+                \OCP\Util::writeLog('core', __METHOD__ . 'Cannot delete tag ' . $name
772
+                    . ': not found.', ILogger::ERROR);
773
+            }
774
+            if(!is_null($id) && $id !== false) {
775
+                try {
776
+                    $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` '
777
+                            . 'WHERE `categoryid` = ?';
778
+                    $stmt = \OC_DB::prepare($sql);
779
+                    $result = $stmt->execute([$id]);
780
+                    if ($result === null) {
781
+                        \OCP\Util::writeLog('core',
782
+                            __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(),
783
+                            ILogger::ERROR);
784
+                        return false;
785
+                    }
786
+                } catch(\Exception $e) {
787
+                    \OC::$server->getLogger()->logException($e, [
788
+                        'message' => __METHOD__,
789
+                        'level' => ILogger::ERROR,
790
+                        'app' => 'core',
791
+                    ]);
792
+                    return false;
793
+                }
794
+            }
795
+        }
796
+        return true;
797
+    }
798
+
799
+    // case-insensitive array_search
800
+    protected function array_searchi($needle, $haystack, $mem='getName') {
801
+        if(!is_array($haystack)) {
802
+            return false;
803
+        }
804
+        return array_search(strtolower($needle), array_map(
805
+            function ($tag) use ($mem) {
806
+                return strtolower(call_user_func([$tag, $mem]));
807
+            }, $haystack)
808
+        );
809
+    }
810
+
811
+    /**
812
+     * Get a tag's ID.
813
+     *
814
+     * @param string $name The tag name to look for.
815
+     * @return string|bool The tag's id or false if no matching tag is found.
816
+     */
817
+    private function getTagId($name) {
818
+        $key = $this->array_searchi($name, $this->tags);
819
+        if ($key !== false) {
820
+            return $this->tags[$key]->getId();
821
+        }
822
+        return false;
823
+    }
824
+
825
+    /**
826
+     * Get a tag by its name.
827
+     *
828
+     * @param string $name The tag name.
829
+     * @return integer|bool The tag object's offset within the $this->tags
830
+     *                      array or false if it doesn't exist.
831
+     */
832
+    private function getTagByName($name) {
833
+        return $this->array_searchi($name, $this->tags, 'getName');
834
+    }
835
+
836
+    /**
837
+     * Get a tag by its ID.
838
+     *
839
+     * @param string $id The tag ID to look for.
840
+     * @return integer|bool The tag object's offset within the $this->tags
841
+     *                      array or false if it doesn't exist.
842
+     */
843
+    private function getTagById($id) {
844
+        return $this->array_searchi($id, $this->tags, 'getId');
845
+    }
846
+
847
+    /**
848
+     * Returns an array mapping a given tag's properties to its values:
849
+     * ['id' => 0, 'name' = 'Tag', 'owner' = 'User', 'type' => 'tagtype']
850
+     *
851
+     * @param Tag $tag The tag that is going to be mapped
852
+     * @return array
853
+     */
854
+    private function tagMap(Tag $tag) {
855
+        return [
856
+            'id'    => $tag->getId(),
857
+            'name'  => $tag->getName(),
858
+            'owner' => $tag->getOwner(),
859
+            'type'  => $tag->getType()
860
+        ];
861
+    }
862 862
 }
Please login to merge, or discard this patch.
Spacing   +86 added lines, -86 removed lines patch added patch discarded remove patch
@@ -136,7 +136,7 @@  discard block
 block discarded – undo
136 136
 		}
137 137
 		$this->tags = $this->mapper->loadTags($this->owners, $this->type);
138 138
 
139
-		if(count($defaultTags) > 0 && count($this->tags) === 0) {
139
+		if (count($defaultTags) > 0 && count($this->tags) === 0) {
140 140
 			$this->addMultiple($defaultTags, true);
141 141
 		}
142 142
 	}
@@ -177,17 +177,17 @@  discard block
 block discarded – undo
177 177
 	 * @return array
178 178
 	 */
179 179
 	public function getTags() {
180
-		if(!count($this->tags)) {
180
+		if (!count($this->tags)) {
181 181
 			return [];
182 182
 		}
183 183
 
184
-		usort($this->tags, function ($a, $b) {
184
+		usort($this->tags, function($a, $b) {
185 185
 			return strnatcasecmp($a->getName(), $b->getName());
186 186
 		});
187 187
 		$tagMap = [];
188 188
 
189
-		foreach($this->tags as $tag) {
190
-			if($tag->getName() !== ITags::TAG_FAVORITE) {
189
+		foreach ($this->tags as $tag) {
190
+			if ($tag->getName() !== ITags::TAG_FAVORITE) {
191 191
 				$tagMap[] = $this->tagMap($tag);
192 192
 			}
193 193
 		}
@@ -204,7 +204,7 @@  discard block
 block discarded – undo
204 204
 	 */
205 205
 	public function getTagsForUser($user) {
206 206
 		return array_filter($this->tags,
207
-			function ($tag) use ($user) {
207
+			function($tag) use ($user) {
208 208
 				return $tag->getOwner() === $user;
209 209
 			}
210 210
 		);
@@ -225,25 +225,25 @@  discard block
 block discarded – undo
225 225
 			$chunks = array_chunk($objIds, 900, false);
226 226
 			foreach ($chunks as $chunk) {
227 227
 				$result = $conn->executeQuery(
228
-					'SELECT `category`, `categoryid`, `objid` ' .
229
-					'FROM `' . self::RELATION_TABLE . '` r, `' . self::TAG_TABLE . '` ' .
228
+					'SELECT `category`, `categoryid`, `objid` '.
229
+					'FROM `'.self::RELATION_TABLE.'` r, `'.self::TAG_TABLE.'` '.
230 230
 					'WHERE `categoryid` = `id` AND `uid` = ? AND r.`type` = ? AND `objid` IN (?)',
231 231
 					[$this->user, $this->type, $chunk],
232 232
 					[null, null, IQueryBuilder::PARAM_INT_ARRAY]
233 233
 				);
234 234
 				while ($row = $result->fetch()) {
235
-					$objId = (int)$row['objid'];
235
+					$objId = (int) $row['objid'];
236 236
 					if (!isset($entries[$objId])) {
237 237
 						$entries[$objId] = [];
238 238
 					}
239 239
 					$entries[$objId][] = $row['category'];
240 240
 				}
241 241
 				if ($result === null) {
242
-					\OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
242
+					\OCP\Util::writeLog('core', __METHOD__.'DB error: '.\OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
243 243
 					return false;
244 244
 				}
245 245
 			}
246
-		} catch(\Exception $e) {
246
+		} catch (\Exception $e) {
247 247
 			\OC::$server->getLogger()->logException($e, [
248 248
 				'message' => __METHOD__,
249 249
 				'level' => ILogger::ERROR,
@@ -267,18 +267,18 @@  discard block
 block discarded – undo
267 267
 	public function getIdsForTag($tag) {
268 268
 		$result = null;
269 269
 		$tagId = false;
270
-		if(is_numeric($tag)) {
270
+		if (is_numeric($tag)) {
271 271
 			$tagId = $tag;
272
-		} elseif(is_string($tag)) {
272
+		} elseif (is_string($tag)) {
273 273
 			$tag = trim($tag);
274
-			if($tag === '') {
274
+			if ($tag === '') {
275 275
 				\OCP\Util::writeLog('core', __METHOD__.', Cannot use empty tag names', ILogger::DEBUG);
276 276
 				return false;
277 277
 			}
278 278
 			$tagId = $this->getTagId($tag);
279 279
 		}
280 280
 
281
-		if($tagId === false) {
281
+		if ($tagId === false) {
282 282
 			$l10n = \OC::$server->getL10N('core');
283 283
 			throw new \Exception(
284 284
 				$l10n->t('Could not find category "%s"', [$tag])
@@ -286,17 +286,17 @@  discard block
 block discarded – undo
286 286
 		}
287 287
 
288 288
 		$ids = [];
289
-		$sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE
289
+		$sql = 'SELECT `objid` FROM `'.self::RELATION_TABLE
290 290
 			. '` WHERE `categoryid` = ?';
291 291
 
292 292
 		try {
293 293
 			$stmt = \OC_DB::prepare($sql);
294 294
 			$result = $stmt->execute([$tagId]);
295 295
 			if ($result === null) {
296
-				\OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
296
+				\OCP\Util::writeLog('core', __METHOD__.'DB error: '.\OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
297 297
 				return false;
298 298
 			}
299
-		} catch(\Exception $e) {
299
+		} catch (\Exception $e) {
300 300
 			\OC::$server->getLogger()->logException($e, [
301 301
 				'message' => __METHOD__,
302 302
 				'level' => ILogger::ERROR,
@@ -305,9 +305,9 @@  discard block
 block discarded – undo
305 305
 			return false;
306 306
 		}
307 307
 
308
-		if(!is_null($result)) {
309
-			while( $row = $result->fetchRow()) {
310
-				$id = (int)$row['objid'];
308
+		if (!is_null($result)) {
309
+			while ($row = $result->fetchRow()) {
310
+				$id = (int) $row['objid'];
311 311
 
312 312
 				if ($this->includeShared) {
313 313
 					// We have to check if we are really allowed to access the
@@ -361,19 +361,19 @@  discard block
 block discarded – undo
361 361
 	public function add($name) {
362 362
 		$name = trim($name);
363 363
 
364
-		if($name === '') {
364
+		if ($name === '') {
365 365
 			\OCP\Util::writeLog('core', __METHOD__.', Cannot add an empty tag', ILogger::DEBUG);
366 366
 			return false;
367 367
 		}
368
-		if($this->userHasTag($name, $this->user)) {
369
-			\OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', ILogger::DEBUG);
368
+		if ($this->userHasTag($name, $this->user)) {
369
+			\OCP\Util::writeLog('core', __METHOD__.', name: '.$name.' exists already', ILogger::DEBUG);
370 370
 			return false;
371 371
 		}
372 372
 		try {
373 373
 			$tag = new Tag($this->user, $this->type, $name);
374 374
 			$tag = $this->mapper->insert($tag);
375 375
 			$this->tags[] = $tag;
376
-		} catch(\Exception $e) {
376
+		} catch (\Exception $e) {
377 377
 			\OC::$server->getLogger()->logException($e, [
378 378
 				'message' => __METHOD__,
379 379
 				'level' => ILogger::ERROR,
@@ -381,7 +381,7 @@  discard block
 block discarded – undo
381 381
 			]);
382 382
 			return false;
383 383
 		}
384
-		\OCP\Util::writeLog('core', __METHOD__.', id: ' . $tag->getId(), ILogger::DEBUG);
384
+		\OCP\Util::writeLog('core', __METHOD__.', id: '.$tag->getId(), ILogger::DEBUG);
385 385
 		return $tag->getId();
386 386
 	}
387 387
 
@@ -396,7 +396,7 @@  discard block
 block discarded – undo
396 396
 		$from = trim($from);
397 397
 		$to = trim($to);
398 398
 
399
-		if($to === '' || $from === '') {
399
+		if ($to === '' || $from === '') {
400 400
 			\OCP\Util::writeLog('core', __METHOD__.', Cannot use empty tag names', ILogger::DEBUG);
401 401
 			return false;
402 402
 		}
@@ -406,21 +406,21 @@  discard block
 block discarded – undo
406 406
 		} else {
407 407
 			$key = $this->getTagByName($from);
408 408
 		}
409
-		if($key === false) {
410
-			\OCP\Util::writeLog('core', __METHOD__.', tag: ' . $from. ' does not exist', ILogger::DEBUG);
409
+		if ($key === false) {
410
+			\OCP\Util::writeLog('core', __METHOD__.', tag: '.$from.' does not exist', ILogger::DEBUG);
411 411
 			return false;
412 412
 		}
413 413
 		$tag = $this->tags[$key];
414 414
 
415
-		if($this->userHasTag($to, $tag->getOwner())) {
416
-			\OCP\Util::writeLog('core', __METHOD__.', A tag named ' . $to. ' already exists for user ' . $tag->getOwner() . '.', ILogger::DEBUG);
415
+		if ($this->userHasTag($to, $tag->getOwner())) {
416
+			\OCP\Util::writeLog('core', __METHOD__.', A tag named '.$to.' already exists for user '.$tag->getOwner().'.', ILogger::DEBUG);
417 417
 			return false;
418 418
 		}
419 419
 
420 420
 		try {
421 421
 			$tag->setName($to);
422 422
 			$this->tags[$key] = $this->mapper->update($tag);
423
-		} catch(\Exception $e) {
423
+		} catch (\Exception $e) {
424 424
 			\OC::$server->getLogger()->logException($e, [
425 425
 				'message' => __METHOD__,
426 426
 				'level' => ILogger::ERROR,
@@ -440,25 +440,25 @@  discard block
 block discarded – undo
440 440
 	 * @param int|null $id int Optional object id to add to this|these tag(s)
441 441
 	 * @return bool Returns false on error.
442 442
 	 */
443
-	public function addMultiple($names, $sync=false, $id = null) {
444
-		if(!is_array($names)) {
443
+	public function addMultiple($names, $sync = false, $id = null) {
444
+		if (!is_array($names)) {
445 445
 			$names = [$names];
446 446
 		}
447 447
 		$names = array_map('trim', $names);
448 448
 		array_filter($names);
449 449
 
450 450
 		$newones = [];
451
-		foreach($names as $name) {
452
-			if(!$this->hasTag($name) && $name !== '') {
451
+		foreach ($names as $name) {
452
+			if (!$this->hasTag($name) && $name !== '') {
453 453
 				$newones[] = new Tag($this->user, $this->type, $name);
454 454
 			}
455
-			if(!is_null($id) ) {
455
+			if (!is_null($id)) {
456 456
 				// Insert $objectid, $categoryid  pairs if not exist.
457 457
 				self::$relations[] = ['objid' => $id, 'tag' => $name];
458 458
 			}
459 459
 		}
460 460
 		$this->tags = array_merge($this->tags, $newones);
461
-		if($sync === true) {
461
+		if ($sync === true) {
462 462
 			$this->save();
463 463
 		}
464 464
 
@@ -469,13 +469,13 @@  discard block
 block discarded – undo
469 469
 	 * Save the list of tags and their object relations
470 470
 	 */
471 471
 	protected function save() {
472
-		if(is_array($this->tags)) {
473
-			foreach($this->tags as $tag) {
472
+		if (is_array($this->tags)) {
473
+			foreach ($this->tags as $tag) {
474 474
 				try {
475 475
 					if (!$this->mapper->tagExists($tag)) {
476 476
 						$this->mapper->insert($tag);
477 477
 					}
478
-				} catch(\Exception $e) {
478
+				} catch (\Exception $e) {
479 479
 					\OC::$server->getLogger()->logException($e, [
480 480
 						'message' => __METHOD__,
481 481
 						'level' => ILogger::ERROR,
@@ -486,7 +486,7 @@  discard block
 block discarded – undo
486 486
 
487 487
 			// reload tags to get the proper ids.
488 488
 			$this->tags = $this->mapper->loadTags($this->owners, $this->type);
489
-			\OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true),
489
+			\OCP\Util::writeLog('core', __METHOD__.', tags: '.print_r($this->tags, true),
490 490
 				ILogger::DEBUG);
491 491
 			// Loop through temporarily cached objectid/tagname pairs
492 492
 			// and save relations.
@@ -494,10 +494,10 @@  discard block
 block discarded – undo
494 494
 			// For some reason this is needed or array_search(i) will return 0..?
495 495
 			ksort($tags);
496 496
 			$dbConnection = \OC::$server->getDatabaseConnection();
497
-			foreach(self::$relations as $relation) {
497
+			foreach (self::$relations as $relation) {
498 498
 				$tagId = $this->getTagId($relation['tag']);
499
-				\OCP\Util::writeLog('core', __METHOD__ . 'catid, ' . $relation['tag'] . ' ' . $tagId, ILogger::DEBUG);
500
-				if($tagId) {
499
+				\OCP\Util::writeLog('core', __METHOD__.'catid, '.$relation['tag'].' '.$tagId, ILogger::DEBUG);
500
+				if ($tagId) {
501 501
 					try {
502 502
 						$dbConnection->insertIfNotExist(self::RELATION_TABLE,
503 503
 							[
@@ -505,7 +505,7 @@  discard block
 block discarded – undo
505 505
 								'categoryid' => $tagId,
506 506
 								'type' => $this->type,
507 507
 							]);
508
-					} catch(\Exception $e) {
508
+					} catch (\Exception $e) {
509 509
 						\OC::$server->getLogger()->logException($e, [
510 510
 							'message' => __METHOD__,
511 511
 							'level' => ILogger::ERROR,
@@ -532,13 +532,13 @@  discard block
 block discarded – undo
532 532
 		// Find all objectid/tagId pairs.
533 533
 		$result = null;
534 534
 		try {
535
-			$stmt = \OC_DB::prepare('SELECT `id` FROM `' . self::TAG_TABLE . '` '
535
+			$stmt = \OC_DB::prepare('SELECT `id` FROM `'.self::TAG_TABLE.'` '
536 536
 				. 'WHERE `uid` = ?');
537 537
 			$result = $stmt->execute([$arguments['uid']]);
538 538
 			if ($result === null) {
539
-				\OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
539
+				\OCP\Util::writeLog('core', __METHOD__.'DB error: '.\OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
540 540
 			}
541
-		} catch(\Exception $e) {
541
+		} catch (\Exception $e) {
542 542
 			\OC::$server->getLogger()->logException($e, [
543 543
 				'message' => __METHOD__,
544 544
 				'level' => ILogger::ERROR,
@@ -546,14 +546,14 @@  discard block
 block discarded – undo
546 546
 			]);
547 547
 		}
548 548
 
549
-		if(!is_null($result)) {
549
+		if (!is_null($result)) {
550 550
 			try {
551
-				$stmt = \OC_DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` '
551
+				$stmt = \OC_DB::prepare('DELETE FROM `'.self::RELATION_TABLE.'` '
552 552
 					. 'WHERE `categoryid` = ?');
553
-				while( $row = $result->fetchRow()) {
553
+				while ($row = $result->fetchRow()) {
554 554
 					try {
555 555
 						$stmt->execute([$row['id']]);
556
-					} catch(\Exception $e) {
556
+					} catch (\Exception $e) {
557 557
 						\OC::$server->getLogger()->logException($e, [
558 558
 							'message' => __METHOD__,
559 559
 							'level' => ILogger::ERROR,
@@ -561,7 +561,7 @@  discard block
 block discarded – undo
561 561
 						]);
562 562
 					}
563 563
 				}
564
-			} catch(\Exception $e) {
564
+			} catch (\Exception $e) {
565 565
 				\OC::$server->getLogger()->logException($e, [
566 566
 					'message' => __METHOD__,
567 567
 					'level' => ILogger::ERROR,
@@ -570,13 +570,13 @@  discard block
 block discarded – undo
570 570
 			}
571 571
 		}
572 572
 		try {
573
-			$stmt = \OC_DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` '
573
+			$stmt = \OC_DB::prepare('DELETE FROM `'.self::TAG_TABLE.'` '
574 574
 				. 'WHERE `uid` = ?');
575 575
 			$result = $stmt->execute([$arguments['uid']]);
576 576
 			if ($result === null) {
577
-				\OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
577
+				\OCP\Util::writeLog('core', __METHOD__.', DB error: '.\OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
578 578
 			}
579
-		} catch(\Exception $e) {
579
+		} catch (\Exception $e) {
580 580
 			\OC::$server->getLogger()->logException($e, [
581 581
 				'message' => __METHOD__,
582 582
 				'level' => ILogger::ERROR,
@@ -592,23 +592,23 @@  discard block
 block discarded – undo
592 592
 	 * @return boolean Returns false on error.
593 593
 	 */
594 594
 	public function purgeObjects(array $ids) {
595
-		if(count($ids) === 0) {
595
+		if (count($ids) === 0) {
596 596
 			// job done ;)
597 597
 			return true;
598 598
 		}
599 599
 		$updates = $ids;
600 600
 		try {
601
-			$query = 'DELETE FROM `' . self::RELATION_TABLE . '` ';
602
-			$query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids)-1) . '?) ';
601
+			$query = 'DELETE FROM `'.self::RELATION_TABLE.'` ';
602
+			$query .= 'WHERE `objid` IN ('.str_repeat('?,', count($ids) - 1).'?) ';
603 603
 			$query .= 'AND `type`= ?';
604 604
 			$updates[] = $this->type;
605 605
 			$stmt = \OC_DB::prepare($query);
606 606
 			$result = $stmt->execute($updates);
607 607
 			if ($result === null) {
608
-				\OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
608
+				\OCP\Util::writeLog('core', __METHOD__.'DB error: '.\OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
609 609
 				return false;
610 610
 			}
611
-		} catch(\Exception $e) {
611
+		} catch (\Exception $e) {
612 612
 			\OC::$server->getLogger()->logException($e, [
613 613
 				'message' => __METHOD__,
614 614
 				'level' => ILogger::ERROR,
@@ -625,13 +625,13 @@  discard block
 block discarded – undo
625 625
 	 * @return array|false An array of object ids.
626 626
 	 */
627 627
 	public function getFavorites() {
628
-		if(!$this->userHasTag(ITags::TAG_FAVORITE, $this->user)) {
628
+		if (!$this->userHasTag(ITags::TAG_FAVORITE, $this->user)) {
629 629
 			return [];
630 630
 		}
631 631
 
632 632
 		try {
633 633
 			return $this->getIdsForTag(ITags::TAG_FAVORITE);
634
-		} catch(\Exception $e) {
634
+		} catch (\Exception $e) {
635 635
 			\OC::$server->getLogger()->logException($e, [
636 636
 				'message' => __METHOD__,
637 637
 				'level' => ILogger::ERROR,
@@ -648,7 +648,7 @@  discard block
 block discarded – undo
648 648
 	 * @return boolean
649 649
 	 */
650 650
 	public function addToFavorites($objid) {
651
-		if(!$this->userHasTag(ITags::TAG_FAVORITE, $this->user)) {
651
+		if (!$this->userHasTag(ITags::TAG_FAVORITE, $this->user)) {
652 652
 			$this->add(ITags::TAG_FAVORITE);
653 653
 		}
654 654
 		return $this->tagAs($objid, ITags::TAG_FAVORITE);
@@ -672,16 +672,16 @@  discard block
 block discarded – undo
672 672
 	 * @return boolean Returns false on error.
673 673
 	 */
674 674
 	public function tagAs($objid, $tag) {
675
-		if(is_string($tag) && !is_numeric($tag)) {
675
+		if (is_string($tag) && !is_numeric($tag)) {
676 676
 			$tag = trim($tag);
677
-			if($tag === '') {
677
+			if ($tag === '') {
678 678
 				\OCP\Util::writeLog('core', __METHOD__.', Cannot add an empty tag', ILogger::DEBUG);
679 679
 				return false;
680 680
 			}
681
-			if(!$this->hasTag($tag)) {
681
+			if (!$this->hasTag($tag)) {
682 682
 				$this->add($tag);
683 683
 			}
684
-			$tagId =  $this->getTagId($tag);
684
+			$tagId = $this->getTagId($tag);
685 685
 		} else {
686 686
 			$tagId = $tag;
687 687
 		}
@@ -692,7 +692,7 @@  discard block
 block discarded – undo
692 692
 					'categoryid' => $tagId,
693 693
 					'type' => $this->type,
694 694
 				]);
695
-		} catch(\Exception $e) {
695
+		} catch (\Exception $e) {
696 696
 			\OC::$server->getLogger()->logException($e, [
697 697
 				'message' => __METHOD__,
698 698
 				'level' => ILogger::ERROR,
@@ -711,23 +711,23 @@  discard block
 block discarded – undo
711 711
 	 * @return boolean
712 712
 	 */
713 713
 	public function unTag($objid, $tag) {
714
-		if(is_string($tag) && !is_numeric($tag)) {
714
+		if (is_string($tag) && !is_numeric($tag)) {
715 715
 			$tag = trim($tag);
716
-			if($tag === '') {
716
+			if ($tag === '') {
717 717
 				\OCP\Util::writeLog('core', __METHOD__.', Tag name is empty', ILogger::DEBUG);
718 718
 				return false;
719 719
 			}
720
-			$tagId =  $this->getTagId($tag);
720
+			$tagId = $this->getTagId($tag);
721 721
 		} else {
722 722
 			$tagId = $tag;
723 723
 		}
724 724
 
725 725
 		try {
726
-			$sql = 'DELETE FROM `' . self::RELATION_TABLE . '` '
726
+			$sql = 'DELETE FROM `'.self::RELATION_TABLE.'` '
727 727
 					. 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?';
728 728
 			$stmt = \OC_DB::prepare($sql);
729 729
 			$stmt->execute([$objid, $tagId, $this->type]);
730
-		} catch(\Exception $e) {
730
+		} catch (\Exception $e) {
731 731
 			\OC::$server->getLogger()->logException($e, [
732 732
 				'message' => __METHOD__,
733 733
 				'level' => ILogger::ERROR,
@@ -745,16 +745,16 @@  discard block
 block discarded – undo
745 745
 	 * @return bool Returns false on error
746 746
 	 */
747 747
 	public function delete($names) {
748
-		if(!is_array($names)) {
748
+		if (!is_array($names)) {
749 749
 			$names = [$names];
750 750
 		}
751 751
 
752 752
 		$names = array_map('trim', $names);
753 753
 		array_filter($names);
754 754
 
755
-		\OCP\Util::writeLog('core', __METHOD__ . ', before: '
755
+		\OCP\Util::writeLog('core', __METHOD__.', before: '
756 756
 			. print_r($this->tags, true), ILogger::DEBUG);
757
-		foreach($names as $name) {
757
+		foreach ($names as $name) {
758 758
 			$id = null;
759 759
 
760 760
 			if (is_numeric($name)) {
@@ -768,22 +768,22 @@  discard block
 block discarded – undo
768 768
 				unset($this->tags[$key]);
769 769
 				$this->mapper->delete($tag);
770 770
 			} else {
771
-				\OCP\Util::writeLog('core', __METHOD__ . 'Cannot delete tag ' . $name
771
+				\OCP\Util::writeLog('core', __METHOD__.'Cannot delete tag '.$name
772 772
 					. ': not found.', ILogger::ERROR);
773 773
 			}
774
-			if(!is_null($id) && $id !== false) {
774
+			if (!is_null($id) && $id !== false) {
775 775
 				try {
776
-					$sql = 'DELETE FROM `' . self::RELATION_TABLE . '` '
776
+					$sql = 'DELETE FROM `'.self::RELATION_TABLE.'` '
777 777
 							. 'WHERE `categoryid` = ?';
778 778
 					$stmt = \OC_DB::prepare($sql);
779 779
 					$result = $stmt->execute([$id]);
780 780
 					if ($result === null) {
781 781
 						\OCP\Util::writeLog('core',
782
-							__METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(),
782
+							__METHOD__.'DB error: '.\OC::$server->getDatabaseConnection()->getError(),
783 783
 							ILogger::ERROR);
784 784
 						return false;
785 785
 					}
786
-				} catch(\Exception $e) {
786
+				} catch (\Exception $e) {
787 787
 					\OC::$server->getLogger()->logException($e, [
788 788
 						'message' => __METHOD__,
789 789
 						'level' => ILogger::ERROR,
@@ -797,12 +797,12 @@  discard block
 block discarded – undo
797 797
 	}
798 798
 
799 799
 	// case-insensitive array_search
800
-	protected function array_searchi($needle, $haystack, $mem='getName') {
801
-		if(!is_array($haystack)) {
800
+	protected function array_searchi($needle, $haystack, $mem = 'getName') {
801
+		if (!is_array($haystack)) {
802 802
 			return false;
803 803
 		}
804 804
 		return array_search(strtolower($needle), array_map(
805
-			function ($tag) use ($mem) {
805
+			function($tag) use ($mem) {
806 806
 				return strtolower(call_user_func([$tag, $mem]));
807 807
 			}, $haystack)
808 808
 		);
Please login to merge, or discard this patch.
lib/private/Group/Group.php 2 patches
Indentation   +357 added lines, -357 removed lines patch added patch discarded remove patch
@@ -45,361 +45,361 @@
 block discarded – undo
45 45
 use Symfony\Component\EventDispatcher\GenericEvent;
46 46
 
47 47
 class Group implements IGroup {
48
-	/** @var null|string  */
49
-	protected $displayName;
50
-
51
-	/** @var string */
52
-	private $gid;
53
-
54
-	/** @var \OC\User\User[] */
55
-	private $users = [];
56
-
57
-	/** @var bool */
58
-	private $usersLoaded;
59
-
60
-	/** @var Backend[] */
61
-	private $backends;
62
-	/** @var EventDispatcherInterface */
63
-	private $dispatcher;
64
-	/** @var \OC\User\Manager|IUserManager  */
65
-	private $userManager;
66
-	/** @var PublicEmitter */
67
-	private $emitter;
68
-
69
-
70
-	/**
71
-	 * @param string $gid
72
-	 * @param Backend[] $backends
73
-	 * @param EventDispatcherInterface $dispatcher
74
-	 * @param IUserManager $userManager
75
-	 * @param PublicEmitter $emitter
76
-	 * @param string $displayName
77
-	 */
78
-	public function __construct(string $gid, array $backends, EventDispatcherInterface $dispatcher, IUserManager $userManager, PublicEmitter $emitter = null, ?string $displayName = null) {
79
-		$this->gid = $gid;
80
-		$this->backends = $backends;
81
-		$this->dispatcher = $dispatcher;
82
-		$this->userManager = $userManager;
83
-		$this->emitter = $emitter;
84
-		$this->displayName = $displayName;
85
-	}
86
-
87
-	public function getGID() {
88
-		return $this->gid;
89
-	}
90
-
91
-	public function getDisplayName() {
92
-		if (is_null($this->displayName)) {
93
-			foreach ($this->backends as $backend) {
94
-				if ($backend instanceof IGetDisplayNameBackend) {
95
-					$displayName = $backend->getDisplayName($this->gid);
96
-					if (trim($displayName) !== '') {
97
-						$this->displayName = $displayName;
98
-						return $this->displayName;
99
-					}
100
-				}
101
-			}
102
-			return $this->gid;
103
-		}
104
-		return $this->displayName;
105
-	}
106
-
107
-	public function setDisplayName(string $displayName): bool {
108
-		$displayName = trim($displayName);
109
-		if ($displayName !== '') {
110
-			foreach ($this->backends as $backend) {
111
-				if (($backend instanceof ISetDisplayNameBackend)
112
-					&& $backend->setDisplayName($this->gid, $displayName)) {
113
-					$this->displayName = $displayName;
114
-					return true;
115
-				}
116
-			}
117
-		}
118
-		return false;
119
-	}
120
-
121
-	/**
122
-	 * get all users in the group
123
-	 *
124
-	 * @return \OC\User\User[]
125
-	 */
126
-	public function getUsers() {
127
-		if ($this->usersLoaded) {
128
-			return $this->users;
129
-		}
130
-
131
-		$userIds = [];
132
-		foreach ($this->backends as $backend) {
133
-			$diff = array_diff(
134
-				$backend->usersInGroup($this->gid),
135
-				$userIds
136
-			);
137
-			if ($diff) {
138
-				$userIds = array_merge($userIds, $diff);
139
-			}
140
-		}
141
-
142
-		$this->users = $this->getVerifiedUsers($userIds);
143
-		$this->usersLoaded = true;
144
-		return $this->users;
145
-	}
146
-
147
-	/**
148
-	 * check if a user is in the group
149
-	 *
150
-	 * @param IUser $user
151
-	 * @return bool
152
-	 */
153
-	public function inGroup(IUser $user) {
154
-		if (isset($this->users[$user->getUID()])) {
155
-			return true;
156
-		}
157
-		foreach ($this->backends as $backend) {
158
-			if ($backend->inGroup($user->getUID(), $this->gid)) {
159
-				$this->users[$user->getUID()] = $user;
160
-				return true;
161
-			}
162
-		}
163
-		return false;
164
-	}
165
-
166
-	/**
167
-	 * add a user to the group
168
-	 *
169
-	 * @param IUser $user
170
-	 */
171
-	public function addUser(IUser $user) {
172
-		if ($this->inGroup($user)) {
173
-			return;
174
-		}
175
-
176
-		$this->dispatcher->dispatch(IGroup::class . '::preAddUser', new GenericEvent($this, [
177
-			'user' => $user,
178
-		]));
179
-
180
-		if ($this->emitter) {
181
-			$this->emitter->emit('\OC\Group', 'preAddUser', [$this, $user]);
182
-		}
183
-		foreach ($this->backends as $backend) {
184
-			if ($backend->implementsActions(\OC\Group\Backend::ADD_TO_GROUP)) {
185
-				$backend->addToGroup($user->getUID(), $this->gid);
186
-				if ($this->users) {
187
-					$this->users[$user->getUID()] = $user;
188
-				}
189
-
190
-				$this->dispatcher->dispatch(IGroup::class . '::postAddUser', new GenericEvent($this, [
191
-					'user' => $user,
192
-				]));
193
-
194
-				if ($this->emitter) {
195
-					$this->emitter->emit('\OC\Group', 'postAddUser', [$this, $user]);
196
-				}
197
-				return;
198
-			}
199
-		}
200
-	}
201
-
202
-	/**
203
-	 * remove a user from the group
204
-	 *
205
-	 * @param \OC\User\User $user
206
-	 */
207
-	public function removeUser($user) {
208
-		$result = false;
209
-		$this->dispatcher->dispatch(IGroup::class . '::preRemoveUser', new GenericEvent($this, [
210
-			'user' => $user,
211
-		]));
212
-		if ($this->emitter) {
213
-			$this->emitter->emit('\OC\Group', 'preRemoveUser', [$this, $user]);
214
-		}
215
-		foreach ($this->backends as $backend) {
216
-			if ($backend->implementsActions(\OC\Group\Backend::REMOVE_FROM_GOUP) and $backend->inGroup($user->getUID(), $this->gid)) {
217
-				$backend->removeFromGroup($user->getUID(), $this->gid);
218
-				$result = true;
219
-			}
220
-		}
221
-		if ($result) {
222
-			$this->dispatcher->dispatch(IGroup::class . '::postRemoveUser', new GenericEvent($this, [
223
-				'user' => $user,
224
-			]));
225
-			if ($this->emitter) {
226
-				$this->emitter->emit('\OC\Group', 'postRemoveUser', [$this, $user]);
227
-			}
228
-			if ($this->users) {
229
-				foreach ($this->users as $index => $groupUser) {
230
-					if ($groupUser->getUID() === $user->getUID()) {
231
-						unset($this->users[$index]);
232
-						return;
233
-					}
234
-				}
235
-			}
236
-		}
237
-	}
238
-
239
-	/**
240
-	 * search for users in the group by userid
241
-	 *
242
-	 * @param string $search
243
-	 * @param int $limit
244
-	 * @param int $offset
245
-	 * @return \OC\User\User[]
246
-	 */
247
-	public function searchUsers($search, $limit = null, $offset = null) {
248
-		$users = [];
249
-		foreach ($this->backends as $backend) {
250
-			$userIds = $backend->usersInGroup($this->gid, $search, $limit, $offset);
251
-			$users += $this->getVerifiedUsers($userIds);
252
-			if (!is_null($limit) and $limit <= 0) {
253
-				return $users;
254
-			}
255
-		}
256
-		return $users;
257
-	}
258
-
259
-	/**
260
-	 * returns the number of users matching the search string
261
-	 *
262
-	 * @param string $search
263
-	 * @return int|bool
264
-	 */
265
-	public function count($search = '') {
266
-		$users = false;
267
-		foreach ($this->backends as $backend) {
268
-			if($backend->implementsActions(\OC\Group\Backend::COUNT_USERS)) {
269
-				if($users === false) {
270
-					//we could directly add to a bool variable, but this would
271
-					//be ugly
272
-					$users = 0;
273
-				}
274
-				$users += $backend->countUsersInGroup($this->gid, $search);
275
-			}
276
-		}
277
-		return $users;
278
-	}
279
-
280
-	/**
281
-	 * returns the number of disabled users
282
-	 *
283
-	 * @return int|bool
284
-	 */
285
-	public function countDisabled() {
286
-		$users = false;
287
-		foreach ($this->backends as $backend) {
288
-			if($backend instanceOf ICountDisabledInGroup) {
289
-				if($users === false) {
290
-					//we could directly add to a bool variable, but this would
291
-					//be ugly
292
-					$users = 0;
293
-				}
294
-				$users += $backend->countDisabledInGroup($this->gid);
295
-			}
296
-		}
297
-		return $users;
298
-	}
299
-
300
-	/**
301
-	 * search for users in the group by displayname
302
-	 *
303
-	 * @param string $search
304
-	 * @param int $limit
305
-	 * @param int $offset
306
-	 * @return \OC\User\User[]
307
-	 */
308
-	public function searchDisplayName($search, $limit = null, $offset = null) {
309
-		$users = [];
310
-		foreach ($this->backends as $backend) {
311
-			$userIds = $backend->usersInGroup($this->gid, $search, $limit, $offset);
312
-			$users = $this->getVerifiedUsers($userIds);
313
-			if (!is_null($limit) and $limit <= 0) {
314
-				return array_values($users);
315
-			}
316
-		}
317
-		return array_values($users);
318
-	}
319
-
320
-	/**
321
-	 * delete the group
322
-	 *
323
-	 * @return bool
324
-	 */
325
-	public function delete() {
326
-		// Prevent users from deleting group admin
327
-		if ($this->getGID() === 'admin') {
328
-			return false;
329
-		}
330
-
331
-		$result = false;
332
-		$this->dispatcher->dispatch(IGroup::class . '::preDelete', new GenericEvent($this));
333
-		if ($this->emitter) {
334
-			$this->emitter->emit('\OC\Group', 'preDelete', [$this]);
335
-		}
336
-		foreach ($this->backends as $backend) {
337
-			if ($backend->implementsActions(\OC\Group\Backend::DELETE_GROUP)) {
338
-				$result = true;
339
-				$backend->deleteGroup($this->gid);
340
-			}
341
-		}
342
-		if ($result) {
343
-			$this->dispatcher->dispatch(IGroup::class . '::postDelete', new GenericEvent($this));
344
-			if ($this->emitter) {
345
-				$this->emitter->emit('\OC\Group', 'postDelete', [$this]);
346
-			}
347
-		}
348
-		return $result;
349
-	}
350
-
351
-	/**
352
-	 * returns all the Users from an array that really exists
353
-	 * @param string[] $userIds an array containing user IDs
354
-	 * @return \OC\User\User[] an Array with the userId as Key and \OC\User\User as value
355
-	 */
356
-	private function getVerifiedUsers($userIds) {
357
-		if (!is_array($userIds)) {
358
-			return [];
359
-		}
360
-		$users = [];
361
-		foreach ($userIds as $userId) {
362
-			$user = $this->userManager->get($userId);
363
-			if (!is_null($user)) {
364
-				$users[$userId] = $user;
365
-			}
366
-		}
367
-		return $users;
368
-	}
369
-
370
-	/**
371
-	 * @return bool
372
-	 * @since 14.0.0
373
-	 */
374
-	public function canRemoveUser() {
375
-		foreach ($this->backends as $backend) {
376
-			if ($backend->implementsActions(GroupInterface::REMOVE_FROM_GOUP)) {
377
-				return true;
378
-			}
379
-		}
380
-		return false;
381
-	}
382
-
383
-	/**
384
-	 * @return bool
385
-	 * @since 14.0.0
386
-	 */
387
-	public function canAddUser() {
388
-		foreach ($this->backends as $backend) {
389
-			if ($backend->implementsActions(GroupInterface::ADD_TO_GROUP)) {
390
-				return true;
391
-			}
392
-		}
393
-		return false;
394
-	}
395
-
396
-	/**
397
-	 * @return bool
398
-	 * @since 16.0.0
399
-	 */
400
-	public function hideFromCollaboration(): bool {
401
-		return array_reduce($this->backends, function (bool $hide, GroupInterface $backend) {
402
-			return $hide | ($backend instanceof IHideFromCollaborationBackend && $backend->hideGroup($this->gid));
403
-		}, false);
404
-	}
48
+    /** @var null|string  */
49
+    protected $displayName;
50
+
51
+    /** @var string */
52
+    private $gid;
53
+
54
+    /** @var \OC\User\User[] */
55
+    private $users = [];
56
+
57
+    /** @var bool */
58
+    private $usersLoaded;
59
+
60
+    /** @var Backend[] */
61
+    private $backends;
62
+    /** @var EventDispatcherInterface */
63
+    private $dispatcher;
64
+    /** @var \OC\User\Manager|IUserManager  */
65
+    private $userManager;
66
+    /** @var PublicEmitter */
67
+    private $emitter;
68
+
69
+
70
+    /**
71
+     * @param string $gid
72
+     * @param Backend[] $backends
73
+     * @param EventDispatcherInterface $dispatcher
74
+     * @param IUserManager $userManager
75
+     * @param PublicEmitter $emitter
76
+     * @param string $displayName
77
+     */
78
+    public function __construct(string $gid, array $backends, EventDispatcherInterface $dispatcher, IUserManager $userManager, PublicEmitter $emitter = null, ?string $displayName = null) {
79
+        $this->gid = $gid;
80
+        $this->backends = $backends;
81
+        $this->dispatcher = $dispatcher;
82
+        $this->userManager = $userManager;
83
+        $this->emitter = $emitter;
84
+        $this->displayName = $displayName;
85
+    }
86
+
87
+    public function getGID() {
88
+        return $this->gid;
89
+    }
90
+
91
+    public function getDisplayName() {
92
+        if (is_null($this->displayName)) {
93
+            foreach ($this->backends as $backend) {
94
+                if ($backend instanceof IGetDisplayNameBackend) {
95
+                    $displayName = $backend->getDisplayName($this->gid);
96
+                    if (trim($displayName) !== '') {
97
+                        $this->displayName = $displayName;
98
+                        return $this->displayName;
99
+                    }
100
+                }
101
+            }
102
+            return $this->gid;
103
+        }
104
+        return $this->displayName;
105
+    }
106
+
107
+    public function setDisplayName(string $displayName): bool {
108
+        $displayName = trim($displayName);
109
+        if ($displayName !== '') {
110
+            foreach ($this->backends as $backend) {
111
+                if (($backend instanceof ISetDisplayNameBackend)
112
+                    && $backend->setDisplayName($this->gid, $displayName)) {
113
+                    $this->displayName = $displayName;
114
+                    return true;
115
+                }
116
+            }
117
+        }
118
+        return false;
119
+    }
120
+
121
+    /**
122
+     * get all users in the group
123
+     *
124
+     * @return \OC\User\User[]
125
+     */
126
+    public function getUsers() {
127
+        if ($this->usersLoaded) {
128
+            return $this->users;
129
+        }
130
+
131
+        $userIds = [];
132
+        foreach ($this->backends as $backend) {
133
+            $diff = array_diff(
134
+                $backend->usersInGroup($this->gid),
135
+                $userIds
136
+            );
137
+            if ($diff) {
138
+                $userIds = array_merge($userIds, $diff);
139
+            }
140
+        }
141
+
142
+        $this->users = $this->getVerifiedUsers($userIds);
143
+        $this->usersLoaded = true;
144
+        return $this->users;
145
+    }
146
+
147
+    /**
148
+     * check if a user is in the group
149
+     *
150
+     * @param IUser $user
151
+     * @return bool
152
+     */
153
+    public function inGroup(IUser $user) {
154
+        if (isset($this->users[$user->getUID()])) {
155
+            return true;
156
+        }
157
+        foreach ($this->backends as $backend) {
158
+            if ($backend->inGroup($user->getUID(), $this->gid)) {
159
+                $this->users[$user->getUID()] = $user;
160
+                return true;
161
+            }
162
+        }
163
+        return false;
164
+    }
165
+
166
+    /**
167
+     * add a user to the group
168
+     *
169
+     * @param IUser $user
170
+     */
171
+    public function addUser(IUser $user) {
172
+        if ($this->inGroup($user)) {
173
+            return;
174
+        }
175
+
176
+        $this->dispatcher->dispatch(IGroup::class . '::preAddUser', new GenericEvent($this, [
177
+            'user' => $user,
178
+        ]));
179
+
180
+        if ($this->emitter) {
181
+            $this->emitter->emit('\OC\Group', 'preAddUser', [$this, $user]);
182
+        }
183
+        foreach ($this->backends as $backend) {
184
+            if ($backend->implementsActions(\OC\Group\Backend::ADD_TO_GROUP)) {
185
+                $backend->addToGroup($user->getUID(), $this->gid);
186
+                if ($this->users) {
187
+                    $this->users[$user->getUID()] = $user;
188
+                }
189
+
190
+                $this->dispatcher->dispatch(IGroup::class . '::postAddUser', new GenericEvent($this, [
191
+                    'user' => $user,
192
+                ]));
193
+
194
+                if ($this->emitter) {
195
+                    $this->emitter->emit('\OC\Group', 'postAddUser', [$this, $user]);
196
+                }
197
+                return;
198
+            }
199
+        }
200
+    }
201
+
202
+    /**
203
+     * remove a user from the group
204
+     *
205
+     * @param \OC\User\User $user
206
+     */
207
+    public function removeUser($user) {
208
+        $result = false;
209
+        $this->dispatcher->dispatch(IGroup::class . '::preRemoveUser', new GenericEvent($this, [
210
+            'user' => $user,
211
+        ]));
212
+        if ($this->emitter) {
213
+            $this->emitter->emit('\OC\Group', 'preRemoveUser', [$this, $user]);
214
+        }
215
+        foreach ($this->backends as $backend) {
216
+            if ($backend->implementsActions(\OC\Group\Backend::REMOVE_FROM_GOUP) and $backend->inGroup($user->getUID(), $this->gid)) {
217
+                $backend->removeFromGroup($user->getUID(), $this->gid);
218
+                $result = true;
219
+            }
220
+        }
221
+        if ($result) {
222
+            $this->dispatcher->dispatch(IGroup::class . '::postRemoveUser', new GenericEvent($this, [
223
+                'user' => $user,
224
+            ]));
225
+            if ($this->emitter) {
226
+                $this->emitter->emit('\OC\Group', 'postRemoveUser', [$this, $user]);
227
+            }
228
+            if ($this->users) {
229
+                foreach ($this->users as $index => $groupUser) {
230
+                    if ($groupUser->getUID() === $user->getUID()) {
231
+                        unset($this->users[$index]);
232
+                        return;
233
+                    }
234
+                }
235
+            }
236
+        }
237
+    }
238
+
239
+    /**
240
+     * search for users in the group by userid
241
+     *
242
+     * @param string $search
243
+     * @param int $limit
244
+     * @param int $offset
245
+     * @return \OC\User\User[]
246
+     */
247
+    public function searchUsers($search, $limit = null, $offset = null) {
248
+        $users = [];
249
+        foreach ($this->backends as $backend) {
250
+            $userIds = $backend->usersInGroup($this->gid, $search, $limit, $offset);
251
+            $users += $this->getVerifiedUsers($userIds);
252
+            if (!is_null($limit) and $limit <= 0) {
253
+                return $users;
254
+            }
255
+        }
256
+        return $users;
257
+    }
258
+
259
+    /**
260
+     * returns the number of users matching the search string
261
+     *
262
+     * @param string $search
263
+     * @return int|bool
264
+     */
265
+    public function count($search = '') {
266
+        $users = false;
267
+        foreach ($this->backends as $backend) {
268
+            if($backend->implementsActions(\OC\Group\Backend::COUNT_USERS)) {
269
+                if($users === false) {
270
+                    //we could directly add to a bool variable, but this would
271
+                    //be ugly
272
+                    $users = 0;
273
+                }
274
+                $users += $backend->countUsersInGroup($this->gid, $search);
275
+            }
276
+        }
277
+        return $users;
278
+    }
279
+
280
+    /**
281
+     * returns the number of disabled users
282
+     *
283
+     * @return int|bool
284
+     */
285
+    public function countDisabled() {
286
+        $users = false;
287
+        foreach ($this->backends as $backend) {
288
+            if($backend instanceOf ICountDisabledInGroup) {
289
+                if($users === false) {
290
+                    //we could directly add to a bool variable, but this would
291
+                    //be ugly
292
+                    $users = 0;
293
+                }
294
+                $users += $backend->countDisabledInGroup($this->gid);
295
+            }
296
+        }
297
+        return $users;
298
+    }
299
+
300
+    /**
301
+     * search for users in the group by displayname
302
+     *
303
+     * @param string $search
304
+     * @param int $limit
305
+     * @param int $offset
306
+     * @return \OC\User\User[]
307
+     */
308
+    public function searchDisplayName($search, $limit = null, $offset = null) {
309
+        $users = [];
310
+        foreach ($this->backends as $backend) {
311
+            $userIds = $backend->usersInGroup($this->gid, $search, $limit, $offset);
312
+            $users = $this->getVerifiedUsers($userIds);
313
+            if (!is_null($limit) and $limit <= 0) {
314
+                return array_values($users);
315
+            }
316
+        }
317
+        return array_values($users);
318
+    }
319
+
320
+    /**
321
+     * delete the group
322
+     *
323
+     * @return bool
324
+     */
325
+    public function delete() {
326
+        // Prevent users from deleting group admin
327
+        if ($this->getGID() === 'admin') {
328
+            return false;
329
+        }
330
+
331
+        $result = false;
332
+        $this->dispatcher->dispatch(IGroup::class . '::preDelete', new GenericEvent($this));
333
+        if ($this->emitter) {
334
+            $this->emitter->emit('\OC\Group', 'preDelete', [$this]);
335
+        }
336
+        foreach ($this->backends as $backend) {
337
+            if ($backend->implementsActions(\OC\Group\Backend::DELETE_GROUP)) {
338
+                $result = true;
339
+                $backend->deleteGroup($this->gid);
340
+            }
341
+        }
342
+        if ($result) {
343
+            $this->dispatcher->dispatch(IGroup::class . '::postDelete', new GenericEvent($this));
344
+            if ($this->emitter) {
345
+                $this->emitter->emit('\OC\Group', 'postDelete', [$this]);
346
+            }
347
+        }
348
+        return $result;
349
+    }
350
+
351
+    /**
352
+     * returns all the Users from an array that really exists
353
+     * @param string[] $userIds an array containing user IDs
354
+     * @return \OC\User\User[] an Array with the userId as Key and \OC\User\User as value
355
+     */
356
+    private function getVerifiedUsers($userIds) {
357
+        if (!is_array($userIds)) {
358
+            return [];
359
+        }
360
+        $users = [];
361
+        foreach ($userIds as $userId) {
362
+            $user = $this->userManager->get($userId);
363
+            if (!is_null($user)) {
364
+                $users[$userId] = $user;
365
+            }
366
+        }
367
+        return $users;
368
+    }
369
+
370
+    /**
371
+     * @return bool
372
+     * @since 14.0.0
373
+     */
374
+    public function canRemoveUser() {
375
+        foreach ($this->backends as $backend) {
376
+            if ($backend->implementsActions(GroupInterface::REMOVE_FROM_GOUP)) {
377
+                return true;
378
+            }
379
+        }
380
+        return false;
381
+    }
382
+
383
+    /**
384
+     * @return bool
385
+     * @since 14.0.0
386
+     */
387
+    public function canAddUser() {
388
+        foreach ($this->backends as $backend) {
389
+            if ($backend->implementsActions(GroupInterface::ADD_TO_GROUP)) {
390
+                return true;
391
+            }
392
+        }
393
+        return false;
394
+    }
395
+
396
+    /**
397
+     * @return bool
398
+     * @since 16.0.0
399
+     */
400
+    public function hideFromCollaboration(): bool {
401
+        return array_reduce($this->backends, function (bool $hide, GroupInterface $backend) {
402
+            return $hide | ($backend instanceof IHideFromCollaborationBackend && $backend->hideGroup($this->gid));
403
+        }, false);
404
+    }
405 405
 }
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -173,7 +173,7 @@  discard block
 block discarded – undo
173 173
 			return;
174 174
 		}
175 175
 
176
-		$this->dispatcher->dispatch(IGroup::class . '::preAddUser', new GenericEvent($this, [
176
+		$this->dispatcher->dispatch(IGroup::class.'::preAddUser', new GenericEvent($this, [
177 177
 			'user' => $user,
178 178
 		]));
179 179
 
@@ -187,7 +187,7 @@  discard block
 block discarded – undo
187 187
 					$this->users[$user->getUID()] = $user;
188 188
 				}
189 189
 
190
-				$this->dispatcher->dispatch(IGroup::class . '::postAddUser', new GenericEvent($this, [
190
+				$this->dispatcher->dispatch(IGroup::class.'::postAddUser', new GenericEvent($this, [
191 191
 					'user' => $user,
192 192
 				]));
193 193
 
@@ -206,7 +206,7 @@  discard block
 block discarded – undo
206 206
 	 */
207 207
 	public function removeUser($user) {
208 208
 		$result = false;
209
-		$this->dispatcher->dispatch(IGroup::class . '::preRemoveUser', new GenericEvent($this, [
209
+		$this->dispatcher->dispatch(IGroup::class.'::preRemoveUser', new GenericEvent($this, [
210 210
 			'user' => $user,
211 211
 		]));
212 212
 		if ($this->emitter) {
@@ -219,7 +219,7 @@  discard block
 block discarded – undo
219 219
 			}
220 220
 		}
221 221
 		if ($result) {
222
-			$this->dispatcher->dispatch(IGroup::class . '::postRemoveUser', new GenericEvent($this, [
222
+			$this->dispatcher->dispatch(IGroup::class.'::postRemoveUser', new GenericEvent($this, [
223 223
 				'user' => $user,
224 224
 			]));
225 225
 			if ($this->emitter) {
@@ -265,8 +265,8 @@  discard block
 block discarded – undo
265 265
 	public function count($search = '') {
266 266
 		$users = false;
267 267
 		foreach ($this->backends as $backend) {
268
-			if($backend->implementsActions(\OC\Group\Backend::COUNT_USERS)) {
269
-				if($users === false) {
268
+			if ($backend->implementsActions(\OC\Group\Backend::COUNT_USERS)) {
269
+				if ($users === false) {
270 270
 					//we could directly add to a bool variable, but this would
271 271
 					//be ugly
272 272
 					$users = 0;
@@ -285,8 +285,8 @@  discard block
 block discarded – undo
285 285
 	public function countDisabled() {
286 286
 		$users = false;
287 287
 		foreach ($this->backends as $backend) {
288
-			if($backend instanceOf ICountDisabledInGroup) {
289
-				if($users === false) {
288
+			if ($backend instanceOf ICountDisabledInGroup) {
289
+				if ($users === false) {
290 290
 					//we could directly add to a bool variable, but this would
291 291
 					//be ugly
292 292
 					$users = 0;
@@ -329,7 +329,7 @@  discard block
 block discarded – undo
329 329
 		}
330 330
 
331 331
 		$result = false;
332
-		$this->dispatcher->dispatch(IGroup::class . '::preDelete', new GenericEvent($this));
332
+		$this->dispatcher->dispatch(IGroup::class.'::preDelete', new GenericEvent($this));
333 333
 		if ($this->emitter) {
334 334
 			$this->emitter->emit('\OC\Group', 'preDelete', [$this]);
335 335
 		}
@@ -340,7 +340,7 @@  discard block
 block discarded – undo
340 340
 			}
341 341
 		}
342 342
 		if ($result) {
343
-			$this->dispatcher->dispatch(IGroup::class . '::postDelete', new GenericEvent($this));
343
+			$this->dispatcher->dispatch(IGroup::class.'::postDelete', new GenericEvent($this));
344 344
 			if ($this->emitter) {
345 345
 				$this->emitter->emit('\OC\Group', 'postDelete', [$this]);
346 346
 			}
@@ -398,7 +398,7 @@  discard block
 block discarded – undo
398 398
 	 * @since 16.0.0
399 399
 	 */
400 400
 	public function hideFromCollaboration(): bool {
401
-		return array_reduce($this->backends, function (bool $hide, GroupInterface $backend) {
401
+		return array_reduce($this->backends, function(bool $hide, GroupInterface $backend) {
402 402
 			return $hide | ($backend instanceof IHideFromCollaborationBackend && $backend->hideGroup($this->gid));
403 403
 		}, false);
404 404
 	}
Please login to merge, or discard this patch.
lib/private/Group/Database.php 2 patches
Indentation   +412 added lines, -412 removed lines patch added patch discarded remove patch
@@ -61,417 +61,417 @@
 block discarded – undo
61 61
  * Class for group management in a SQL Database (e.g. MySQL, SQLite)
62 62
  */
63 63
 class Database extends ABackend
64
-	implements IAddToGroupBackend,
65
-			   ICountDisabledInGroup,
66
-			   ICountUsersBackend,
67
-			   ICreateGroupBackend,
68
-			   IDeleteGroupBackend,
69
-			   IGetDisplayNameBackend,
70
-			   IGroupDetailsBackend,
71
-			   IRemoveFromGroupBackend,
72
-			   ISetDisplayNameBackend {
73
-
74
-	/** @var string[] */
75
-	private $groupCache = [];
76
-
77
-	/** @var IDBConnection */
78
-	private $dbConn;
79
-
80
-	/**
81
-	 * \OC\Group\Database constructor.
82
-	 *
83
-	 * @param IDBConnection|null $dbConn
84
-	 */
85
-	public function __construct(IDBConnection $dbConn = null) {
86
-		$this->dbConn = $dbConn;
87
-	}
88
-
89
-	/**
90
-	 * FIXME: This function should not be required!
91
-	 */
92
-	private function fixDI() {
93
-		if ($this->dbConn === null) {
94
-			$this->dbConn = \OC::$server->getDatabaseConnection();
95
-		}
96
-	}
97
-
98
-	/**
99
-	 * Try to create a new group
100
-	 * @param string $gid The name of the group to create
101
-	 * @return bool
102
-	 *
103
-	 * Tries to create a new group. If the group name already exists, false will
104
-	 * be returned.
105
-	 */
106
-	public function createGroup(string $gid): bool {
107
-		$this->fixDI();
108
-
109
-		try {
110
-			// Add group
111
-			$builder = $this->dbConn->getQueryBuilder();
112
-			$result = $builder->insert('groups')
113
-				->setValue('gid', $builder->createNamedParameter($gid))
114
-				->setValue('displayname', $builder->createNamedParameter($gid))
115
-				->execute();
116
-		} catch(UniqueConstraintViolationException $e) {
117
-			$result = 0;
118
-		}
119
-
120
-		// Add to cache
121
-		$this->groupCache[$gid] = $gid;
122
-
123
-		return $result === 1;
124
-	}
125
-
126
-	/**
127
-	 * delete a group
128
-	 * @param string $gid gid of the group to delete
129
-	 * @return bool
130
-	 *
131
-	 * Deletes a group and removes it from the group_user-table
132
-	 */
133
-	public function deleteGroup(string $gid): bool {
134
-		$this->fixDI();
135
-
136
-		// Delete the group
137
-		$qb = $this->dbConn->getQueryBuilder();
138
-		$qb->delete('groups')
139
-			->where($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
140
-			->execute();
141
-
142
-		// Delete the group-user relation
143
-		$qb = $this->dbConn->getQueryBuilder();
144
-		$qb->delete('group_user')
145
-			->where($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
146
-			->execute();
147
-
148
-		// Delete the group-groupadmin relation
149
-		$qb = $this->dbConn->getQueryBuilder();
150
-		$qb->delete('group_admin')
151
-			->where($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
152
-			->execute();
153
-
154
-		// Delete from cache
155
-		unset($this->groupCache[$gid]);
156
-
157
-		return true;
158
-	}
159
-
160
-	/**
161
-	 * is user in group?
162
-	 * @param string $uid uid of the user
163
-	 * @param string $gid gid of the group
164
-	 * @return bool
165
-	 *
166
-	 * Checks whether the user is member of a group or not.
167
-	 */
168
-	public function inGroup($uid, $gid) {
169
-		$this->fixDI();
170
-
171
-		// check
172
-		$qb = $this->dbConn->getQueryBuilder();
173
-		$cursor = $qb->select('uid')
174
-			->from('group_user')
175
-			->where($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
176
-			->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($uid)))
177
-			->execute();
178
-
179
-		$result = $cursor->fetch();
180
-		$cursor->closeCursor();
181
-
182
-		return $result ? true : false;
183
-	}
184
-
185
-	/**
186
-	 * Add a user to a group
187
-	 * @param string $uid Name of the user to add to group
188
-	 * @param string $gid Name of the group in which add the user
189
-	 * @return bool
190
-	 *
191
-	 * Adds a user to a group.
192
-	 */
193
-	public function addToGroup(string $uid, string $gid): bool {
194
-		$this->fixDI();
195
-
196
-		// No duplicate entries!
197
-		if( !$this->inGroup( $uid, $gid )) {
198
-			$qb = $this->dbConn->getQueryBuilder();
199
-			$qb->insert('group_user')
200
-				->setValue('uid', $qb->createNamedParameter($uid))
201
-				->setValue('gid', $qb->createNamedParameter($gid))
202
-				->execute();
203
-			return true;
204
-		}else{
205
-			return false;
206
-		}
207
-	}
208
-
209
-	/**
210
-	 * Removes a user from a group
211
-	 * @param string $uid Name of the user to remove from group
212
-	 * @param string $gid Name of the group from which remove the user
213
-	 * @return bool
214
-	 *
215
-	 * removes the user from a group.
216
-	 */
217
-	public function removeFromGroup(string $uid, string $gid): bool {
218
-		$this->fixDI();
219
-
220
-		$qb = $this->dbConn->getQueryBuilder();
221
-		$qb->delete('group_user')
222
-			->where($qb->expr()->eq('uid', $qb->createNamedParameter($uid)))
223
-			->andWhere($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
224
-			->execute();
225
-
226
-		return true;
227
-	}
228
-
229
-	/**
230
-	 * Get all groups a user belongs to
231
-	 * @param string $uid Name of the user
232
-	 * @return array an array of group names
233
-	 *
234
-	 * This function fetches all groups a user belongs to. It does not check
235
-	 * if the user exists at all.
236
-	 */
237
-	public function getUserGroups($uid) {
238
-		//guests has empty or null $uid
239
-		if ($uid === null || $uid === '') {
240
-			return [];
241
-		}
242
-
243
-		$this->fixDI();
244
-
245
-		// No magic!
246
-		$qb = $this->dbConn->getQueryBuilder();
247
-		$cursor = $qb->select('gid')
248
-			->from('group_user')
249
-			->where($qb->expr()->eq('uid', $qb->createNamedParameter($uid)))
250
-			->execute();
251
-
252
-		$groups = [];
253
-		while( $row = $cursor->fetch()) {
254
-			$groups[] = $row['gid'];
255
-			$this->groupCache[$row['gid']] = $row['gid'];
256
-		}
257
-		$cursor->closeCursor();
258
-
259
-		return $groups;
260
-	}
261
-
262
-	/**
263
-	 * get a list of all groups
264
-	 * @param string $search
265
-	 * @param int $limit
266
-	 * @param int $offset
267
-	 * @return array an array of group names
268
-	 *
269
-	 * Returns a list with all groups
270
-	 */
271
-	public function getGroups($search = '', $limit = null, $offset = null) {
272
-		$this->fixDI();
273
-
274
-		$query = $this->dbConn->getQueryBuilder();
275
-		$query->select('gid')
276
-			->from('groups')
277
-			->orderBy('gid', 'ASC');
278
-
279
-		if ($search !== '') {
280
-			$query->where($query->expr()->iLike('gid', $query->createNamedParameter(
281
-				'%' . $this->dbConn->escapeLikeParameter($search) . '%'
282
-			)));
283
-		}
284
-
285
-		$query->setMaxResults($limit)
286
-			->setFirstResult($offset);
287
-		$result = $query->execute();
288
-
289
-		$groups = [];
290
-		while ($row = $result->fetch()) {
291
-			$groups[] = $row['gid'];
292
-		}
293
-		$result->closeCursor();
294
-
295
-		return $groups;
296
-	}
297
-
298
-	/**
299
-	 * check if a group exists
300
-	 * @param string $gid
301
-	 * @return bool
302
-	 */
303
-	public function groupExists($gid) {
304
-		$this->fixDI();
305
-
306
-		// Check cache first
307
-		if (isset($this->groupCache[$gid])) {
308
-			return true;
309
-		}
310
-
311
-		$qb = $this->dbConn->getQueryBuilder();
312
-		$cursor = $qb->select('gid')
313
-			->from('groups')
314
-			->where($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
315
-			->execute();
316
-		$result = $cursor->fetch();
317
-		$cursor->closeCursor();
318
-
319
-		if ($result !== false) {
320
-			$this->groupCache[$gid] = $gid;
321
-			return true;
322
-		}
323
-		return false;
324
-	}
325
-
326
-	/**
327
-	 * get a list of all users in a group
328
-	 * @param string $gid
329
-	 * @param string $search
330
-	 * @param int $limit
331
-	 * @param int $offset
332
-	 * @return array an array of user ids
333
-	 */
334
-	public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) {
335
-		$this->fixDI();
336
-
337
-		$query = $this->dbConn->getQueryBuilder();
338
-		$query->select('uid')
339
-			->from('group_user')
340
-			->where($query->expr()->eq('gid', $query->createNamedParameter($gid)))
341
-			->orderBy('uid', 'ASC');
342
-
343
-		if ($search !== '') {
344
-			$query->andWhere($query->expr()->like('uid', $query->createNamedParameter(
345
-				'%' . $this->dbConn->escapeLikeParameter($search) . '%'
346
-			)));
347
-		}
348
-
349
-		if ($limit !== -1) {
350
-			$query->setMaxResults($limit);
351
-		}
352
-		if ($offset !== 0) {
353
-			$query->setFirstResult($offset);
354
-		}
355
-
356
-		$result = $query->execute();
357
-
358
-		$users = [];
359
-		while ($row = $result->fetch()) {
360
-			$users[] = $row['uid'];
361
-		}
362
-		$result->closeCursor();
363
-
364
-		return $users;
365
-	}
366
-
367
-	/**
368
-	 * get the number of all users matching the search string in a group
369
-	 * @param string $gid
370
-	 * @param string $search
371
-	 * @return int
372
-	 */
373
-	public function countUsersInGroup(string $gid, string $search = ''): int {
374
-		$this->fixDI();
375
-
376
-		$query = $this->dbConn->getQueryBuilder();
377
-		$query->select($query->func()->count('*', 'num_users'))
378
-			->from('group_user')
379
-			->where($query->expr()->eq('gid', $query->createNamedParameter($gid)));
380
-
381
-		if ($search !== '') {
382
-			$query->andWhere($query->expr()->like('uid', $query->createNamedParameter(
383
-				'%' . $this->dbConn->escapeLikeParameter($search) . '%'
384
-			)));
385
-		}
386
-
387
-		$result = $query->execute();
388
-		$count = $result->fetchColumn();
389
-		$result->closeCursor();
390
-
391
-		if ($count !== false) {
392
-			$count = (int)$count;
393
-		} else {
394
-			$count = 0;
395
-		}
396
-
397
-		return $count;
398
-	}
399
-
400
-	/**
401
-	 * get the number of disabled users in a group
402
-	 *
403
-	 * @param string $search
404
-	 *
405
-	 * @return int
406
-	 */
407
-	public function countDisabledInGroup(string $gid): int {
408
-		$this->fixDI();
409
-
410
-		$query = $this->dbConn->getQueryBuilder();
411
-		$query->select($query->createFunction('COUNT(DISTINCT ' . $query->getColumnName('uid') . ')'))
412
-			->from('preferences', 'p')
413
-			->innerJoin('p', 'group_user', 'g', $query->expr()->eq('p.userid', 'g.uid'))
414
-			->where($query->expr()->eq('appid', $query->createNamedParameter('core')))
415
-			->andWhere($query->expr()->eq('configkey', $query->createNamedParameter('enabled')))
416
-			->andWhere($query->expr()->eq('configvalue', $query->createNamedParameter('false'), IQueryBuilder::PARAM_STR))
417
-			->andWhere($query->expr()->eq('gid', $query->createNamedParameter($gid), IQueryBuilder::PARAM_STR));
418
-
419
-		$result = $query->execute();
420
-		$count = $result->fetchColumn();
421
-		$result->closeCursor();
422
-
423
-		if ($count !== false) {
424
-			$count = (int)$count;
425
-		} else {
426
-			$count = 0;
427
-		}
428
-
429
-		return $count;
430
-	}
431
-
432
-	public function getDisplayName(string $gid): string {
433
-		$this->fixDI();
434
-
435
-		$query = $this->dbConn->getQueryBuilder();
436
-		$query->select('displayname')
437
-			->from('groups')
438
-			->where($query->expr()->eq('gid', $query->createNamedParameter($gid)));
439
-
440
-		$result = $query->execute();
441
-		$displayName = $result->fetchColumn();
442
-		$result->closeCursor();
443
-
444
-		return (string) $displayName;
445
-	}
446
-
447
-	public function getGroupDetails(string $gid): array {
448
-		$displayName = $this->getDisplayName($gid);
449
-		if ($displayName !== '') {
450
-			return ['displayName' => $displayName];
451
-		}
452
-
453
-		return [];
454
-	}
455
-
456
-	public function setDisplayName(string $gid, string $displayName): bool {
457
-		if (!$this->groupExists($gid)) {
458
-			return false;
459
-		}
460
-
461
-		$this->fixDI();
462
-
463
-		$displayName = trim($displayName);
464
-		if ($displayName === '') {
465
-			$displayName = $gid;
466
-		}
467
-
468
-		$query = $this->dbConn->getQueryBuilder();
469
-		$query->update('groups')
470
-			->set('displayname', $query->createNamedParameter($displayName))
471
-			->where($query->expr()->eq('gid', $query->createNamedParameter($gid)));
472
-		$query->execute();
473
-
474
-		return true;
475
-	}
64
+    implements IAddToGroupBackend,
65
+                ICountDisabledInGroup,
66
+                ICountUsersBackend,
67
+                ICreateGroupBackend,
68
+                IDeleteGroupBackend,
69
+                IGetDisplayNameBackend,
70
+                IGroupDetailsBackend,
71
+                IRemoveFromGroupBackend,
72
+                ISetDisplayNameBackend {
73
+
74
+    /** @var string[] */
75
+    private $groupCache = [];
76
+
77
+    /** @var IDBConnection */
78
+    private $dbConn;
79
+
80
+    /**
81
+     * \OC\Group\Database constructor.
82
+     *
83
+     * @param IDBConnection|null $dbConn
84
+     */
85
+    public function __construct(IDBConnection $dbConn = null) {
86
+        $this->dbConn = $dbConn;
87
+    }
88
+
89
+    /**
90
+     * FIXME: This function should not be required!
91
+     */
92
+    private function fixDI() {
93
+        if ($this->dbConn === null) {
94
+            $this->dbConn = \OC::$server->getDatabaseConnection();
95
+        }
96
+    }
97
+
98
+    /**
99
+     * Try to create a new group
100
+     * @param string $gid The name of the group to create
101
+     * @return bool
102
+     *
103
+     * Tries to create a new group. If the group name already exists, false will
104
+     * be returned.
105
+     */
106
+    public function createGroup(string $gid): bool {
107
+        $this->fixDI();
108
+
109
+        try {
110
+            // Add group
111
+            $builder = $this->dbConn->getQueryBuilder();
112
+            $result = $builder->insert('groups')
113
+                ->setValue('gid', $builder->createNamedParameter($gid))
114
+                ->setValue('displayname', $builder->createNamedParameter($gid))
115
+                ->execute();
116
+        } catch(UniqueConstraintViolationException $e) {
117
+            $result = 0;
118
+        }
119
+
120
+        // Add to cache
121
+        $this->groupCache[$gid] = $gid;
122
+
123
+        return $result === 1;
124
+    }
125
+
126
+    /**
127
+     * delete a group
128
+     * @param string $gid gid of the group to delete
129
+     * @return bool
130
+     *
131
+     * Deletes a group and removes it from the group_user-table
132
+     */
133
+    public function deleteGroup(string $gid): bool {
134
+        $this->fixDI();
135
+
136
+        // Delete the group
137
+        $qb = $this->dbConn->getQueryBuilder();
138
+        $qb->delete('groups')
139
+            ->where($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
140
+            ->execute();
141
+
142
+        // Delete the group-user relation
143
+        $qb = $this->dbConn->getQueryBuilder();
144
+        $qb->delete('group_user')
145
+            ->where($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
146
+            ->execute();
147
+
148
+        // Delete the group-groupadmin relation
149
+        $qb = $this->dbConn->getQueryBuilder();
150
+        $qb->delete('group_admin')
151
+            ->where($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
152
+            ->execute();
153
+
154
+        // Delete from cache
155
+        unset($this->groupCache[$gid]);
156
+
157
+        return true;
158
+    }
159
+
160
+    /**
161
+     * is user in group?
162
+     * @param string $uid uid of the user
163
+     * @param string $gid gid of the group
164
+     * @return bool
165
+     *
166
+     * Checks whether the user is member of a group or not.
167
+     */
168
+    public function inGroup($uid, $gid) {
169
+        $this->fixDI();
170
+
171
+        // check
172
+        $qb = $this->dbConn->getQueryBuilder();
173
+        $cursor = $qb->select('uid')
174
+            ->from('group_user')
175
+            ->where($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
176
+            ->andWhere($qb->expr()->eq('uid', $qb->createNamedParameter($uid)))
177
+            ->execute();
178
+
179
+        $result = $cursor->fetch();
180
+        $cursor->closeCursor();
181
+
182
+        return $result ? true : false;
183
+    }
184
+
185
+    /**
186
+     * Add a user to a group
187
+     * @param string $uid Name of the user to add to group
188
+     * @param string $gid Name of the group in which add the user
189
+     * @return bool
190
+     *
191
+     * Adds a user to a group.
192
+     */
193
+    public function addToGroup(string $uid, string $gid): bool {
194
+        $this->fixDI();
195
+
196
+        // No duplicate entries!
197
+        if( !$this->inGroup( $uid, $gid )) {
198
+            $qb = $this->dbConn->getQueryBuilder();
199
+            $qb->insert('group_user')
200
+                ->setValue('uid', $qb->createNamedParameter($uid))
201
+                ->setValue('gid', $qb->createNamedParameter($gid))
202
+                ->execute();
203
+            return true;
204
+        }else{
205
+            return false;
206
+        }
207
+    }
208
+
209
+    /**
210
+     * Removes a user from a group
211
+     * @param string $uid Name of the user to remove from group
212
+     * @param string $gid Name of the group from which remove the user
213
+     * @return bool
214
+     *
215
+     * removes the user from a group.
216
+     */
217
+    public function removeFromGroup(string $uid, string $gid): bool {
218
+        $this->fixDI();
219
+
220
+        $qb = $this->dbConn->getQueryBuilder();
221
+        $qb->delete('group_user')
222
+            ->where($qb->expr()->eq('uid', $qb->createNamedParameter($uid)))
223
+            ->andWhere($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
224
+            ->execute();
225
+
226
+        return true;
227
+    }
228
+
229
+    /**
230
+     * Get all groups a user belongs to
231
+     * @param string $uid Name of the user
232
+     * @return array an array of group names
233
+     *
234
+     * This function fetches all groups a user belongs to. It does not check
235
+     * if the user exists at all.
236
+     */
237
+    public function getUserGroups($uid) {
238
+        //guests has empty or null $uid
239
+        if ($uid === null || $uid === '') {
240
+            return [];
241
+        }
242
+
243
+        $this->fixDI();
244
+
245
+        // No magic!
246
+        $qb = $this->dbConn->getQueryBuilder();
247
+        $cursor = $qb->select('gid')
248
+            ->from('group_user')
249
+            ->where($qb->expr()->eq('uid', $qb->createNamedParameter($uid)))
250
+            ->execute();
251
+
252
+        $groups = [];
253
+        while( $row = $cursor->fetch()) {
254
+            $groups[] = $row['gid'];
255
+            $this->groupCache[$row['gid']] = $row['gid'];
256
+        }
257
+        $cursor->closeCursor();
258
+
259
+        return $groups;
260
+    }
261
+
262
+    /**
263
+     * get a list of all groups
264
+     * @param string $search
265
+     * @param int $limit
266
+     * @param int $offset
267
+     * @return array an array of group names
268
+     *
269
+     * Returns a list with all groups
270
+     */
271
+    public function getGroups($search = '', $limit = null, $offset = null) {
272
+        $this->fixDI();
273
+
274
+        $query = $this->dbConn->getQueryBuilder();
275
+        $query->select('gid')
276
+            ->from('groups')
277
+            ->orderBy('gid', 'ASC');
278
+
279
+        if ($search !== '') {
280
+            $query->where($query->expr()->iLike('gid', $query->createNamedParameter(
281
+                '%' . $this->dbConn->escapeLikeParameter($search) . '%'
282
+            )));
283
+        }
284
+
285
+        $query->setMaxResults($limit)
286
+            ->setFirstResult($offset);
287
+        $result = $query->execute();
288
+
289
+        $groups = [];
290
+        while ($row = $result->fetch()) {
291
+            $groups[] = $row['gid'];
292
+        }
293
+        $result->closeCursor();
294
+
295
+        return $groups;
296
+    }
297
+
298
+    /**
299
+     * check if a group exists
300
+     * @param string $gid
301
+     * @return bool
302
+     */
303
+    public function groupExists($gid) {
304
+        $this->fixDI();
305
+
306
+        // Check cache first
307
+        if (isset($this->groupCache[$gid])) {
308
+            return true;
309
+        }
310
+
311
+        $qb = $this->dbConn->getQueryBuilder();
312
+        $cursor = $qb->select('gid')
313
+            ->from('groups')
314
+            ->where($qb->expr()->eq('gid', $qb->createNamedParameter($gid)))
315
+            ->execute();
316
+        $result = $cursor->fetch();
317
+        $cursor->closeCursor();
318
+
319
+        if ($result !== false) {
320
+            $this->groupCache[$gid] = $gid;
321
+            return true;
322
+        }
323
+        return false;
324
+    }
325
+
326
+    /**
327
+     * get a list of all users in a group
328
+     * @param string $gid
329
+     * @param string $search
330
+     * @param int $limit
331
+     * @param int $offset
332
+     * @return array an array of user ids
333
+     */
334
+    public function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) {
335
+        $this->fixDI();
336
+
337
+        $query = $this->dbConn->getQueryBuilder();
338
+        $query->select('uid')
339
+            ->from('group_user')
340
+            ->where($query->expr()->eq('gid', $query->createNamedParameter($gid)))
341
+            ->orderBy('uid', 'ASC');
342
+
343
+        if ($search !== '') {
344
+            $query->andWhere($query->expr()->like('uid', $query->createNamedParameter(
345
+                '%' . $this->dbConn->escapeLikeParameter($search) . '%'
346
+            )));
347
+        }
348
+
349
+        if ($limit !== -1) {
350
+            $query->setMaxResults($limit);
351
+        }
352
+        if ($offset !== 0) {
353
+            $query->setFirstResult($offset);
354
+        }
355
+
356
+        $result = $query->execute();
357
+
358
+        $users = [];
359
+        while ($row = $result->fetch()) {
360
+            $users[] = $row['uid'];
361
+        }
362
+        $result->closeCursor();
363
+
364
+        return $users;
365
+    }
366
+
367
+    /**
368
+     * get the number of all users matching the search string in a group
369
+     * @param string $gid
370
+     * @param string $search
371
+     * @return int
372
+     */
373
+    public function countUsersInGroup(string $gid, string $search = ''): int {
374
+        $this->fixDI();
375
+
376
+        $query = $this->dbConn->getQueryBuilder();
377
+        $query->select($query->func()->count('*', 'num_users'))
378
+            ->from('group_user')
379
+            ->where($query->expr()->eq('gid', $query->createNamedParameter($gid)));
380
+
381
+        if ($search !== '') {
382
+            $query->andWhere($query->expr()->like('uid', $query->createNamedParameter(
383
+                '%' . $this->dbConn->escapeLikeParameter($search) . '%'
384
+            )));
385
+        }
386
+
387
+        $result = $query->execute();
388
+        $count = $result->fetchColumn();
389
+        $result->closeCursor();
390
+
391
+        if ($count !== false) {
392
+            $count = (int)$count;
393
+        } else {
394
+            $count = 0;
395
+        }
396
+
397
+        return $count;
398
+    }
399
+
400
+    /**
401
+     * get the number of disabled users in a group
402
+     *
403
+     * @param string $search
404
+     *
405
+     * @return int
406
+     */
407
+    public function countDisabledInGroup(string $gid): int {
408
+        $this->fixDI();
409
+
410
+        $query = $this->dbConn->getQueryBuilder();
411
+        $query->select($query->createFunction('COUNT(DISTINCT ' . $query->getColumnName('uid') . ')'))
412
+            ->from('preferences', 'p')
413
+            ->innerJoin('p', 'group_user', 'g', $query->expr()->eq('p.userid', 'g.uid'))
414
+            ->where($query->expr()->eq('appid', $query->createNamedParameter('core')))
415
+            ->andWhere($query->expr()->eq('configkey', $query->createNamedParameter('enabled')))
416
+            ->andWhere($query->expr()->eq('configvalue', $query->createNamedParameter('false'), IQueryBuilder::PARAM_STR))
417
+            ->andWhere($query->expr()->eq('gid', $query->createNamedParameter($gid), IQueryBuilder::PARAM_STR));
418
+
419
+        $result = $query->execute();
420
+        $count = $result->fetchColumn();
421
+        $result->closeCursor();
422
+
423
+        if ($count !== false) {
424
+            $count = (int)$count;
425
+        } else {
426
+            $count = 0;
427
+        }
428
+
429
+        return $count;
430
+    }
431
+
432
+    public function getDisplayName(string $gid): string {
433
+        $this->fixDI();
434
+
435
+        $query = $this->dbConn->getQueryBuilder();
436
+        $query->select('displayname')
437
+            ->from('groups')
438
+            ->where($query->expr()->eq('gid', $query->createNamedParameter($gid)));
439
+
440
+        $result = $query->execute();
441
+        $displayName = $result->fetchColumn();
442
+        $result->closeCursor();
443
+
444
+        return (string) $displayName;
445
+    }
446
+
447
+    public function getGroupDetails(string $gid): array {
448
+        $displayName = $this->getDisplayName($gid);
449
+        if ($displayName !== '') {
450
+            return ['displayName' => $displayName];
451
+        }
452
+
453
+        return [];
454
+    }
455
+
456
+    public function setDisplayName(string $gid, string $displayName): bool {
457
+        if (!$this->groupExists($gid)) {
458
+            return false;
459
+        }
460
+
461
+        $this->fixDI();
462
+
463
+        $displayName = trim($displayName);
464
+        if ($displayName === '') {
465
+            $displayName = $gid;
466
+        }
467
+
468
+        $query = $this->dbConn->getQueryBuilder();
469
+        $query->update('groups')
470
+            ->set('displayname', $query->createNamedParameter($displayName))
471
+            ->where($query->expr()->eq('gid', $query->createNamedParameter($gid)));
472
+        $query->execute();
473
+
474
+        return true;
475
+    }
476 476
 
477 477
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -113,7 +113,7 @@  discard block
 block discarded – undo
113 113
 				->setValue('gid', $builder->createNamedParameter($gid))
114 114
 				->setValue('displayname', $builder->createNamedParameter($gid))
115 115
 				->execute();
116
-		} catch(UniqueConstraintViolationException $e) {
116
+		} catch (UniqueConstraintViolationException $e) {
117 117
 			$result = 0;
118 118
 		}
119 119
 
@@ -194,14 +194,14 @@  discard block
 block discarded – undo
194 194
 		$this->fixDI();
195 195
 
196 196
 		// No duplicate entries!
197
-		if( !$this->inGroup( $uid, $gid )) {
197
+		if (!$this->inGroup($uid, $gid)) {
198 198
 			$qb = $this->dbConn->getQueryBuilder();
199 199
 			$qb->insert('group_user')
200 200
 				->setValue('uid', $qb->createNamedParameter($uid))
201 201
 				->setValue('gid', $qb->createNamedParameter($gid))
202 202
 				->execute();
203 203
 			return true;
204
-		}else{
204
+		} else {
205 205
 			return false;
206 206
 		}
207 207
 	}
@@ -250,7 +250,7 @@  discard block
 block discarded – undo
250 250
 			->execute();
251 251
 
252 252
 		$groups = [];
253
-		while( $row = $cursor->fetch()) {
253
+		while ($row = $cursor->fetch()) {
254 254
 			$groups[] = $row['gid'];
255 255
 			$this->groupCache[$row['gid']] = $row['gid'];
256 256
 		}
@@ -278,7 +278,7 @@  discard block
 block discarded – undo
278 278
 
279 279
 		if ($search !== '') {
280 280
 			$query->where($query->expr()->iLike('gid', $query->createNamedParameter(
281
-				'%' . $this->dbConn->escapeLikeParameter($search) . '%'
281
+				'%'.$this->dbConn->escapeLikeParameter($search).'%'
282 282
 			)));
283 283
 		}
284 284
 
@@ -342,7 +342,7 @@  discard block
 block discarded – undo
342 342
 
343 343
 		if ($search !== '') {
344 344
 			$query->andWhere($query->expr()->like('uid', $query->createNamedParameter(
345
-				'%' . $this->dbConn->escapeLikeParameter($search) . '%'
345
+				'%'.$this->dbConn->escapeLikeParameter($search).'%'
346 346
 			)));
347 347
 		}
348 348
 
@@ -380,7 +380,7 @@  discard block
 block discarded – undo
380 380
 
381 381
 		if ($search !== '') {
382 382
 			$query->andWhere($query->expr()->like('uid', $query->createNamedParameter(
383
-				'%' . $this->dbConn->escapeLikeParameter($search) . '%'
383
+				'%'.$this->dbConn->escapeLikeParameter($search).'%'
384 384
 			)));
385 385
 		}
386 386
 
@@ -389,7 +389,7 @@  discard block
 block discarded – undo
389 389
 		$result->closeCursor();
390 390
 
391 391
 		if ($count !== false) {
392
-			$count = (int)$count;
392
+			$count = (int) $count;
393 393
 		} else {
394 394
 			$count = 0;
395 395
 		}
@@ -408,7 +408,7 @@  discard block
 block discarded – undo
408 408
 		$this->fixDI();
409 409
 
410 410
 		$query = $this->dbConn->getQueryBuilder();
411
-		$query->select($query->createFunction('COUNT(DISTINCT ' . $query->getColumnName('uid') . ')'))
411
+		$query->select($query->createFunction('COUNT(DISTINCT '.$query->getColumnName('uid').')'))
412 412
 			->from('preferences', 'p')
413 413
 			->innerJoin('p', 'group_user', 'g', $query->expr()->eq('p.userid', 'g.uid'))
414 414
 			->where($query->expr()->eq('appid', $query->createNamedParameter('core')))
@@ -421,7 +421,7 @@  discard block
 block discarded – undo
421 421
 		$result->closeCursor();
422 422
 
423 423
 		if ($count !== false) {
424
-			$count = (int)$count;
424
+			$count = (int) $count;
425 425
 		} else {
426 426
 			$count = 0;
427 427
 		}
Please login to merge, or discard this patch.