Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like OC_Util often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use OC_Util, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 7 | class OC_Util { |
||
| 8 | public static $scripts = array(); |
||
| 9 | public static $styles = array(); |
||
| 10 | public static $headers = array(); |
||
| 11 | private static $rootMounted = false; |
||
| 12 | private static $fsSetup = false; |
||
| 13 | |||
| 14 | private static function initLocalStorageRootFS() { |
||
| 24 | |||
| 25 | /** |
||
| 26 | * mounting an object storage as the root fs will in essence remove the |
||
| 27 | * necessity of a data folder being present. |
||
| 28 | * TODO make home storage aware of this and use the object storage instead of local disk access |
||
| 29 | * |
||
| 30 | * @param array $config containing 'class' and optional 'arguments' |
||
| 31 | */ |
||
| 32 | private static function initObjectStoreRootFS($config) { |
||
| 53 | |||
| 54 | /** |
||
| 55 | * Can be set up |
||
| 56 | * |
||
| 57 | * @param string $user |
||
| 58 | * @return boolean |
||
| 59 | * @description configure the initial filesystem based on the configuration |
||
| 60 | */ |
||
| 61 | public static function setupFS($user = '') { |
||
| 137 | |||
| 138 | /** |
||
| 139 | * check if a password is required for each public link |
||
| 140 | * |
||
| 141 | * @return boolean |
||
| 142 | */ |
||
| 143 | public static function isPublicLinkPasswordRequired() { |
||
| 148 | |||
| 149 | /** |
||
| 150 | * check if sharing is disabled for the current user |
||
| 151 | * |
||
| 152 | * @return boolean |
||
| 153 | */ |
||
| 154 | public static function isSharingDisabledForUser() { |
||
| 171 | |||
| 172 | /** |
||
| 173 | * check if share API enforces a default expire date |
||
| 174 | * |
||
| 175 | * @return boolean |
||
| 176 | */ |
||
| 177 | public static function isDefaultExpireDateEnforced() { |
||
| 187 | |||
| 188 | /** |
||
| 189 | * Get the quota of a user |
||
| 190 | * |
||
| 191 | * @param string $user |
||
| 192 | * @return int Quota bytes |
||
| 193 | */ |
||
| 194 | public static function getUserQuota($user) { |
||
| 206 | |||
| 207 | /** |
||
| 208 | * copies the skeleton to the users /files |
||
| 209 | * |
||
| 210 | * @param \OC\User\User $user |
||
| 211 | * @param \OCP\Files\Folder $userDirectory |
||
| 212 | */ |
||
| 213 | public static function copySkeleton(\OC\User\User $user, \OCP\Files\Folder $userDirectory) { |
||
| 228 | |||
| 229 | /** |
||
| 230 | * copies a directory recursively by using streams |
||
| 231 | * |
||
| 232 | * @param string $source |
||
| 233 | * @param \OCP\Files\Folder $target |
||
| 234 | * @return void |
||
| 235 | */ |
||
| 236 | public static function copyr($source, \OCP\Files\Folder $target) { |
||
| 251 | |||
| 252 | /** |
||
| 253 | * @return void |
||
| 254 | */ |
||
| 255 | public static function tearDownFS() { |
||
| 260 | |||
| 261 | /** |
||
| 262 | * get the current installed version of ownCloud |
||
| 263 | * |
||
| 264 | * @return array |
||
| 265 | */ |
||
| 266 | public static function getVersion() { |
||
| 270 | |||
| 271 | /** |
||
| 272 | * get the current installed version string of ownCloud |
||
| 273 | * |
||
| 274 | * @return string |
||
| 275 | */ |
||
| 276 | public static function getVersionString() { |
||
| 280 | |||
| 281 | /** |
||
| 282 | * @description get the current installed edition of ownCloud. There is the community |
||
| 283 | * edition that just returns an empty string and the enterprise edition |
||
| 284 | * that returns "Enterprise". |
||
| 285 | * @return string |
||
| 286 | */ |
||
| 287 | public static function getEditionString() { |
||
| 295 | |||
| 296 | /** |
||
| 297 | * @description get the update channel of the current installed of ownCloud. |
||
| 298 | * @return string |
||
| 299 | */ |
||
| 300 | public static function getChannel() { |
||
| 304 | |||
| 305 | /** |
||
| 306 | * @description get the build number of the current installed of ownCloud. |
||
| 307 | * @return string |
||
| 308 | */ |
||
| 309 | public static function getBuild() { |
||
| 313 | |||
| 314 | /** |
||
| 315 | * @description load the version.php into the session as cache |
||
| 316 | */ |
||
| 317 | private static function loadVersion() { |
||
| 334 | |||
| 335 | /** |
||
| 336 | * generates a path for JS/CSS files. If no application is provided it will create the path for core. |
||
| 337 | * |
||
| 338 | * @param string $application application to get the files from |
||
| 339 | * @param string $directory directory withing this application (css, js, vendor, etc) |
||
| 340 | * @param string $file the file inside of the above folder |
||
| 341 | * @return string the path |
||
| 342 | */ |
||
| 343 | private static function generatePath($application, $directory, $file) { |
||
| 354 | |||
| 355 | /** |
||
| 356 | * add a javascript file |
||
| 357 | * |
||
| 358 | * @param string $application application id |
||
| 359 | * @param string|null $file filename |
||
| 360 | * @return void |
||
| 361 | */ |
||
| 362 | public static function addScript($application, $file = null) { |
||
| 372 | |||
| 373 | /** |
||
| 374 | * add a javascript file from the vendor sub folder |
||
| 375 | * |
||
| 376 | * @param string $application application id |
||
| 377 | * @param string|null $file filename |
||
| 378 | * @return void |
||
| 379 | */ |
||
| 380 | public static function addVendorScript($application, $file = null) { |
||
| 386 | |||
| 387 | /** |
||
| 388 | * add a translation JS file |
||
| 389 | * |
||
| 390 | * @param string $application application id |
||
| 391 | * @param string $languageCode language code, defaults to the current language |
||
| 392 | */ |
||
| 393 | public static function addTranslations($application, $languageCode = null) { |
||
| 407 | |||
| 408 | /** |
||
| 409 | * add a css file |
||
| 410 | * |
||
| 411 | * @param string $application application id |
||
| 412 | * @param string|null $file filename |
||
| 413 | * @return void |
||
| 414 | */ |
||
| 415 | public static function addStyle($application, $file = null) { |
||
| 421 | |||
| 422 | /** |
||
| 423 | * add a css file from the vendor sub folder |
||
| 424 | * |
||
| 425 | * @param string $application application id |
||
| 426 | * @param string|null $file filename |
||
| 427 | * @return void |
||
| 428 | */ |
||
| 429 | public static function addVendorStyle($application, $file = null) { |
||
| 435 | |||
| 436 | /** |
||
| 437 | * Add a custom element to the header |
||
| 438 | * If $text is null then the element will be written as empty element. |
||
| 439 | * So use "" to get a closing tag. |
||
| 440 | * @param string $tag tag name of the element |
||
| 441 | * @param array $attributes array of attributes for the element |
||
| 442 | * @param string $text the text content for the element |
||
| 443 | */ |
||
| 444 | View Code Duplication | public static function addHeader($tag, $attributes, $text=null) { |
|
| 451 | |||
| 452 | /** |
||
| 453 | * formats a timestamp in the "right" way |
||
| 454 | * |
||
| 455 | * @param int $timestamp |
||
| 456 | * @param bool $dateOnly option to omit time from the result |
||
| 457 | * @param DateTimeZone|string $timeZone where the given timestamp shall be converted to |
||
| 458 | * @return string timestamp |
||
| 459 | * |
||
| 460 | * @deprecated Use \OC::$server->query('DateTimeFormatter') instead |
||
| 461 | */ |
||
| 462 | public static function formatDate($timestamp, $dateOnly = false, $timeZone = null) { |
||
| 474 | |||
| 475 | /** |
||
| 476 | * check if the current server configuration is suitable for ownCloud |
||
| 477 | * |
||
| 478 | * @param \OCP\IConfig $config |
||
| 479 | * @return array arrays with error messages and hints |
||
| 480 | */ |
||
| 481 | public static function checkServer(\OCP\IConfig $config) { |
||
| 652 | |||
| 653 | /** |
||
| 654 | * Check the database version |
||
| 655 | * |
||
| 656 | * @return array errors array |
||
| 657 | */ |
||
| 658 | public static function checkDatabaseVersion() { |
||
| 687 | |||
| 688 | |||
| 689 | /** |
||
| 690 | * check if there are still some encrypted files stored |
||
| 691 | * |
||
| 692 | * @return boolean |
||
| 693 | */ |
||
| 694 | View Code Duplication | public static function encryptedFiles() { |
|
| 710 | |||
| 711 | /** |
||
| 712 | * check if a backup from the encryption keys exists |
||
| 713 | * |
||
| 714 | * @return boolean |
||
| 715 | */ |
||
| 716 | View Code Duplication | public static function backupKeysExists() { |
|
| 732 | |||
| 733 | /** |
||
| 734 | * Check for correct file permissions of data directory |
||
| 735 | * |
||
| 736 | * @param string $dataDirectory |
||
| 737 | * @return array arrays with error messages and hints |
||
| 738 | */ |
||
| 739 | public static function checkDataDirectoryPermissions($dataDirectory) { |
||
| 762 | |||
| 763 | /** |
||
| 764 | * Check that the data directory exists and is valid by |
||
| 765 | * checking the existence of the ".ocdata" file. |
||
| 766 | * |
||
| 767 | * @param string $dataDirectory data directory path |
||
| 768 | * @return bool true if the data directory is valid, false otherwise |
||
| 769 | */ |
||
| 770 | public static function checkDataDirectoryValidity($dataDirectory) { |
||
| 782 | |||
| 783 | /** |
||
| 784 | * @param array $errors |
||
| 785 | * @param string[] $messages |
||
| 786 | */ |
||
| 787 | public static function displayLoginPage($errors = array(), $messages = []) { |
||
| 809 | |||
| 810 | |||
| 811 | /** |
||
| 812 | * Check if the app is enabled, redirects to home if not |
||
| 813 | * |
||
| 814 | * @param string $app |
||
| 815 | * @return void |
||
| 816 | */ |
||
| 817 | public static function checkAppEnabled($app) { |
||
| 823 | |||
| 824 | /** |
||
| 825 | * Check if the user is logged in, redirects to home if not. With |
||
| 826 | * redirect URL parameter to the request URI. |
||
| 827 | * |
||
| 828 | * @return void |
||
| 829 | */ |
||
| 830 | public static function checkLoggedIn() { |
||
| 839 | |||
| 840 | /** |
||
| 841 | * Check if the user is a admin, redirects to home if not |
||
| 842 | * |
||
| 843 | * @return void |
||
| 844 | */ |
||
| 845 | View Code Duplication | public static function checkAdminUser() { |
|
| 852 | |||
| 853 | /** |
||
| 854 | * Check if it is allowed to remember login. |
||
| 855 | * |
||
| 856 | * @note Every app can set 'rememberlogin' to 'false' to disable the remember login feature |
||
| 857 | * |
||
| 858 | * @return bool |
||
| 859 | */ |
||
| 860 | public static function rememberLoginAllowed() { |
||
| 873 | |||
| 874 | /** |
||
| 875 | * Check if the user is a subadmin, redirects to home if not |
||
| 876 | * |
||
| 877 | * @return null|boolean $groups where the current user is subadmin |
||
| 878 | */ |
||
| 879 | View Code Duplication | public static function checkSubAdminUser() { |
|
| 887 | |||
| 888 | /** |
||
| 889 | * Returns the URL of the default page |
||
| 890 | * based on the system configuration and |
||
| 891 | * the apps visible for the current user |
||
| 892 | * |
||
| 893 | * @return string URL |
||
| 894 | */ |
||
| 895 | public static function getDefaultPageUrl() { |
||
| 921 | |||
| 922 | /** |
||
| 923 | * Redirect to the user default page |
||
| 924 | * |
||
| 925 | * @return void |
||
| 926 | */ |
||
| 927 | public static function redirectToDefaultPage() { |
||
| 932 | |||
| 933 | /** |
||
| 934 | * get an id unique for this instance |
||
| 935 | * |
||
| 936 | * @return string |
||
| 937 | */ |
||
| 938 | public static function getInstanceId() { |
||
| 947 | |||
| 948 | /** |
||
| 949 | * Register an get/post call. Important to prevent CSRF attacks. |
||
| 950 | * |
||
| 951 | * @return string Generated token. |
||
| 952 | * @description |
||
| 953 | * Creates a 'request token' (random) and stores it inside the session. |
||
| 954 | * Ever subsequent (ajax) request must use such a valid token to succeed, |
||
| 955 | * otherwise the request will be denied as a protection against CSRF. |
||
| 956 | * @see OC_Util::isCallRegistered() |
||
| 957 | */ |
||
| 958 | public static function callRegister() { |
||
| 970 | |||
| 971 | /** |
||
| 972 | * Check an ajax get/post call if the request token is valid. |
||
| 973 | * |
||
| 974 | * @return boolean False if request token is not set or is invalid. |
||
| 975 | * @see OC_Util::callRegister() |
||
| 976 | */ |
||
| 977 | public static function isCallRegistered() { |
||
| 980 | |||
| 981 | /** |
||
| 982 | * Check an ajax get/post call if the request token is valid. Exit if not. |
||
| 983 | * |
||
| 984 | * @return void |
||
| 985 | */ |
||
| 986 | public static function callCheck() { |
||
| 991 | |||
| 992 | /** |
||
| 993 | * Public function to sanitize HTML |
||
| 994 | * |
||
| 995 | * This function is used to sanitize HTML and should be applied on any |
||
| 996 | * string or array of strings before displaying it on a web page. |
||
| 997 | * |
||
| 998 | * @param string|array &$value |
||
| 999 | * @return string|array an array of sanitized strings or a single sanitized string, depends on the input parameter. |
||
| 1000 | */ |
||
| 1001 | public static function sanitizeHTML(&$value) { |
||
| 1010 | |||
| 1011 | /** |
||
| 1012 | * Public function to encode url parameters |
||
| 1013 | * |
||
| 1014 | * This function is used to encode path to file before output. |
||
| 1015 | * Encoding is done according to RFC 3986 with one exception: |
||
| 1016 | * Character '/' is preserved as is. |
||
| 1017 | * |
||
| 1018 | * @param string $component part of URI to encode |
||
| 1019 | * @return string |
||
| 1020 | */ |
||
| 1021 | public static function encodePath($component) { |
||
| 1026 | |||
| 1027 | /** |
||
| 1028 | * Check if the .htaccess file is working |
||
| 1029 | * |
||
| 1030 | * @throws OC\HintException If the testfile can't get written. |
||
| 1031 | * @return bool |
||
| 1032 | * @description Check if the .htaccess file is working by creating a test |
||
| 1033 | * file in the data directory and trying to access via http |
||
| 1034 | */ |
||
| 1035 | public static function isHtaccessWorking() { |
||
| 1077 | |||
| 1078 | /** |
||
| 1079 | * Check if the setlocal call does not work. This can happen if the right |
||
| 1080 | * local packages are not available on the server. |
||
| 1081 | * |
||
| 1082 | * @return bool |
||
| 1083 | */ |
||
| 1084 | public static function isSetLocaleWorking() { |
||
| 1096 | |||
| 1097 | /** |
||
| 1098 | * Check if it's possible to get the inline annotations |
||
| 1099 | * |
||
| 1100 | * @return bool |
||
| 1101 | */ |
||
| 1102 | public static function isAnnotationsWorking() { |
||
| 1108 | |||
| 1109 | /** |
||
| 1110 | * Check if the PHP module fileinfo is loaded. |
||
| 1111 | * |
||
| 1112 | * @return bool |
||
| 1113 | */ |
||
| 1114 | public static function fileInfoLoaded() { |
||
| 1117 | |||
| 1118 | /** |
||
| 1119 | * Check if the ownCloud server can connect to the internet |
||
| 1120 | * |
||
| 1121 | * @return bool |
||
| 1122 | */ |
||
| 1123 | public static function isInternetConnectionWorking() { |
||
| 1150 | |||
| 1151 | /** |
||
| 1152 | * Check if the connection to the internet is disabled on purpose |
||
| 1153 | * |
||
| 1154 | * @return string |
||
| 1155 | */ |
||
| 1156 | public static function isInternetConnectionEnabled() { |
||
| 1159 | |||
| 1160 | /** |
||
| 1161 | * clear all levels of output buffering |
||
| 1162 | * |
||
| 1163 | * @return void |
||
| 1164 | */ |
||
| 1165 | public static function obEnd() { |
||
| 1170 | |||
| 1171 | |||
| 1172 | /** |
||
| 1173 | * Generates a cryptographic secure pseudo-random string |
||
| 1174 | * |
||
| 1175 | * @param int $length of the random string |
||
| 1176 | * @return string |
||
| 1177 | * @deprecated Use \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate($length); instead |
||
| 1178 | */ |
||
| 1179 | public static function generateRandomBytes($length = 30) { |
||
| 1182 | |||
| 1183 | /** |
||
| 1184 | * Checks if a secure random number generator is available |
||
| 1185 | * |
||
| 1186 | * @return true |
||
| 1187 | * @deprecated Function will be removed in the future and does only return true. |
||
| 1188 | */ |
||
| 1189 | public static function secureRNGAvailable() { |
||
| 1192 | |||
| 1193 | /** |
||
| 1194 | * Get URL content |
||
| 1195 | * @param string $url Url to get content |
||
| 1196 | * @deprecated Use \OC::$server->getHTTPHelper()->getUrlContent($url); |
||
| 1197 | * @throws Exception If the URL does not start with http:// or https:// |
||
| 1198 | * @return string of the response or false on error |
||
| 1199 | * This function get the content of a page via curl, if curl is enabled. |
||
| 1200 | * If not, file_get_contents is used. |
||
| 1201 | */ |
||
| 1202 | public static function getUrlContent($url) { |
||
| 1209 | |||
| 1210 | /** |
||
| 1211 | * Checks whether the server is running on Windows |
||
| 1212 | * |
||
| 1213 | * @return bool true if running on Windows, false otherwise |
||
| 1214 | */ |
||
| 1215 | public static function runningOnWindows() { |
||
| 1218 | |||
| 1219 | /** |
||
| 1220 | * Checks whether the server is running on Mac OS X |
||
| 1221 | * |
||
| 1222 | * @return bool true if running on Mac OS X, false otherwise |
||
| 1223 | */ |
||
| 1224 | public static function runningOnMac() { |
||
| 1227 | |||
| 1228 | /** |
||
| 1229 | * Checks whether server is running on HHVM |
||
| 1230 | * |
||
| 1231 | * @return bool True if running on HHVM, false otherwise |
||
| 1232 | */ |
||
| 1233 | public static function runningOnHhvm() { |
||
| 1236 | |||
| 1237 | /** |
||
| 1238 | * Handles the case that there may not be a theme, then check if a "default" |
||
| 1239 | * theme exists and take that one |
||
| 1240 | * |
||
| 1241 | * @return string the theme |
||
| 1242 | */ |
||
| 1243 | public static function getTheme() { |
||
| 1254 | |||
| 1255 | /** |
||
| 1256 | * Clear the opcode cache if one exists |
||
| 1257 | * This is necessary for writing to the config file |
||
| 1258 | * in case the opcode cache does not re-validate files |
||
| 1259 | * |
||
| 1260 | * @return void |
||
| 1261 | */ |
||
| 1262 | public static function clearOpcodeCache() { |
||
| 1284 | |||
| 1285 | /** |
||
| 1286 | * Normalize a unicode string |
||
| 1287 | * |
||
| 1288 | * @param string $value a not normalized string |
||
| 1289 | * @return bool|string |
||
| 1290 | */ |
||
| 1291 | public static function normalizeUnicode($value) { |
||
| 1304 | |||
| 1305 | /** |
||
| 1306 | * @param boolean|string $file |
||
| 1307 | * @return string |
||
| 1308 | */ |
||
| 1309 | public static function basename($file) { |
||
| 1314 | |||
| 1315 | /** |
||
| 1316 | * A human readable string is generated based on version, channel and build number |
||
| 1317 | * |
||
| 1318 | * @return string |
||
| 1319 | */ |
||
| 1320 | public static function getHumanVersion() { |
||
| 1328 | |||
| 1329 | /** |
||
| 1330 | * Returns whether the given file name is valid |
||
| 1331 | * |
||
| 1332 | * @param string $file file name to check |
||
| 1333 | * @return bool true if the file name is valid, false otherwise |
||
| 1334 | */ |
||
| 1335 | public static function isValidFileName($file) { |
||
| 1350 | |||
| 1351 | /** |
||
| 1352 | * Check whether the instance needs to perform an upgrade, |
||
| 1353 | * either when the core version is higher or any app requires |
||
| 1354 | * an upgrade. |
||
| 1355 | * |
||
| 1356 | * @param \OCP\IConfig $config |
||
| 1357 | * @return bool whether the core or any app needs an upgrade |
||
| 1358 | */ |
||
| 1359 | public static function needUpgrade(\OCP\IConfig $config) { |
||
| 1381 | |||
| 1382 | /** |
||
| 1383 | * Check if PhpCharset config is UTF-8 |
||
| 1384 | * |
||
| 1385 | * @return string |
||
| 1386 | */ |
||
| 1387 | public static function isPhpCharSetUtf8() { |
||
| 1390 | |||
| 1391 | } |
||
| 1392 |
Let’s take a look at an example:
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.
Available Fixes
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the interface: