diff options
author | Robin McCorkell <rmccorkell@owncloud.com> | 2015-09-03 19:48:42 +0100 |
---|---|---|
committer | Robin McCorkell <rmccorkell@owncloud.com> | 2015-09-04 17:28:20 +0100 |
commit | cdf01f04194a9de30e4247338a5b2675cb1c3ece (patch) | |
tree | 84a76c014b069b3e68f4b4983d7a2a9cd2a8e772 | |
parent | 79fceeff338d262828cc977839b171999da0a7eb (diff) | |
download | nextcloud-server-cdf01f04194a9de30e4247338a5b2675cb1c3ece.tar.gz nextcloud-server-cdf01f04194a9de30e4247338a5b2675cb1c3ece.zip |
Split mimetype handling to new class
-rw-r--r-- | apps/files_sharing/lib/cache.php | 6 | ||||
-rw-r--r-- | lib/private/files/cache/cache.php | 96 | ||||
-rw-r--r-- | lib/private/files/type/loader.php | 165 | ||||
-rw-r--r-- | lib/private/server.php | 14 | ||||
-rw-r--r-- | lib/public/files/imimetypeloader.php | 59 | ||||
-rw-r--r-- | lib/public/iservercontainer.php | 8 | ||||
-rw-r--r-- | tests/lib/repair/repairmimetypes.php | 29 |
7 files changed, 280 insertions, 97 deletions
diff --git a/apps/files_sharing/lib/cache.php b/apps/files_sharing/lib/cache.php index c25dc92409f..377c9f02253 100644 --- a/apps/files_sharing/lib/cache.php +++ b/apps/files_sharing/lib/cache.php @@ -47,6 +47,7 @@ class Shared_Cache extends Cache { * @param \OC\Files\Storage\Shared $storage */ public function __construct($storage) { + parent::__construct($storage); $this->storage = $storage; } @@ -94,6 +95,7 @@ class Shared_Cache extends Cache { * @return array|false */ public function get($file) { + $mimetypeLoader = \OC::$server->getMimeTypeLoader(); if (is_string($file)) { $cache = $this->getSourceCache($file); if ($cache) { @@ -130,8 +132,8 @@ class Shared_Cache extends Cache { $data['mtime'] = (int)$data['mtime']; $data['storage_mtime'] = (int)$data['storage_mtime']; $data['encrypted'] = (bool)$data['encrypted']; - $data['mimetype'] = $this->getMimetype($data['mimetype']); - $data['mimepart'] = $this->getMimetype($data['mimepart']); + $data['mimetype'] = $mimetypeLoader->getMimetypeById($data['mimetype']); + $data['mimepart'] = $mimetypeLoader->getMimetypeById($data['mimepart']); if ($data['storage_mtime'] === 0) { $data['storage_mtime'] = $data['mtime']; } diff --git a/lib/private/files/cache/cache.php b/lib/private/files/cache/cache.php index 8cf097421d4..5c04da1f0d5 100644 --- a/lib/private/files/cache/cache.php +++ b/lib/private/files/cache/cache.php @@ -35,6 +35,8 @@ namespace OC\Files\Cache; +use \OCP\Files\IMimeTypeLoader; + /** * Metadata cache for a storage * @@ -66,8 +68,8 @@ class Cache { */ protected $storageCache; - protected static $mimetypeIds = array(); - protected static $mimetypes = array(); + /** @var IMimeTypeLoader */ + protected $mimetypeLoader; /** * @param \OC\Files\Storage\Storage|string $storage @@ -83,6 +85,7 @@ class Cache { } $this->storageCache = new Storage($storage); + $this->mimetypeLoader = \OC::$server->getMimeTypeLoader(); } /** @@ -95,72 +98,6 @@ class Cache { } /** - * Get the numeric id for a mimetype - * - * Mimetypes are stored as integers in the cache to prevent duplicated data of the (usually) fairly limited amount of unique mimetypes - * If the supplied mimetype does not yet have a numeric id a new one will be generated - * - * @param string $mime - * @return int - */ - public function getMimetypeId($mime) { - if (empty($mime)) { - // Can not insert empty string into Oracle NOT NULL column. - $mime = 'application/octet-stream'; - } - if (empty(self::$mimetypeIds)) { - $this->loadMimetypes(); - } - - if (!isset(self::$mimetypeIds[$mime])) { - try { - $connection = \OC_DB::getConnection(); - $connection->insertIfNotExist('*PREFIX*mimetypes', [ - 'mimetype' => $mime, - ]); - $this->loadMimetypes(); - } catch (\Doctrine\DBAL\DBALException $e) { - \OCP\Util::writeLog('core', 'Exception during mimetype insertion: ' . $e->getmessage(), \OCP\Util::DEBUG); - return -1; - } - } - - return self::$mimetypeIds[$mime]; - } - - - /** - * Get the mimetype (as string) from a mimetype id - * - * @param int $id - * @return string | null the mimetype for the id or null if the id is not known - */ - public function getMimetype($id) { - if (empty(self::$mimetypes)) { - $this->loadMimetypes(); - } - - return isset(self::$mimetypes[$id]) ? self::$mimetypes[$id] : null; - } - - /** - * Load all known mimetypes and mimetype ids from the database - * - * @throws \OC\DatabaseException - */ - public function loadMimetypes() { - self::$mimetypeIds = self::$mimetypes = array(); - - $result = \OC_DB::executeAudited('SELECT `id`, `mimetype` FROM `*PREFIX*mimetypes`', array()); - if ($result) { - while ($row = $result->fetchRow()) { - self::$mimetypeIds[$row['mimetype']] = $row['id']; - self::$mimetypes[$row['id']] = $row['mimetype']; - } - } - } - - /** * get the stored metadata of a file or folder * * the returned cache entry contains at least the following values: @@ -222,8 +159,8 @@ class Cache { $data['storage_mtime'] = (int)$data['storage_mtime']; $data['encrypted'] = (bool)$data['encrypted']; $data['storage'] = $this->storageId; - $data['mimetype'] = $this->getMimetype($data['mimetype']); - $data['mimepart'] = $this->getMimetype($data['mimepart']); + $data['mimetype'] = $this->mimetypeLoader->getMimetypeById($data['mimetype']); + $data['mimepart'] = $this->mimetypeLoader->getMimetypeById($data['mimepart']); if ($data['storage_mtime'] == 0) { $data['storage_mtime'] = $data['mtime']; } @@ -258,8 +195,8 @@ class Cache { $result = \OC_DB::executeAudited($sql, array($fileId)); $files = $result->fetchAll(); foreach ($files as &$file) { - $file['mimetype'] = $this->getMimetype($file['mimetype']); - $file['mimepart'] = $this->getMimetype($file['mimepart']); + $file['mimetype'] = $this->mimetypeLoader->getMimetypeById($file['mimetype']); + $file['mimepart'] = $this->mimetypeLoader->getMimetypeById($file['mimepart']); if ($file['storage_mtime'] == 0) { $file['storage_mtime'] = $file['mtime']; } @@ -385,9 +322,9 @@ class Cache { $params[] = md5($value); $queryParts[] = '`path_hash`'; } elseif ($name === 'mimetype') { - $params[] = $this->getMimetypeId(substr($value, 0, strpos($value, '/'))); + $params[] = $this->mimetypeLoader->getId(substr($value, 0, strpos($value, '/'))); $queryParts[] = '`mimepart`'; - $value = $this->getMimetypeId($value); + $value = $this->mimetypeLoader->getId($value); } elseif ($name === 'storage_mtime') { if (!isset($data['mtime'])) { $params[] = $value; @@ -613,7 +550,6 @@ class Cache { * @return array an array of cache entries where the name matches the search pattern */ public function search($pattern) { - // normalize pattern $pattern = $this->normalize($pattern); @@ -630,8 +566,8 @@ class Cache { $files = array(); while ($row = $result->fetchRow()) { - $row['mimetype'] = $this->getMimetype($row['mimetype']); - $row['mimepart'] = $this->getMimetype($row['mimepart']); + $row['mimetype'] = $this->mimetypeLoader->getMimetypeById($row['mimetype']); + $row['mimepart'] = $this->mimetypeLoader->getMimetypeById($row['mimepart']); $files[] = $row; } return $files; @@ -652,12 +588,12 @@ class Cache { } $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag`, `permissions` FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `storage` = ?'; - $mimetype = $this->getMimetypeId($mimetype); + $mimetype = $this->mimetypeLoader->getId($mimetype); $result = \OC_DB::executeAudited($sql, array($mimetype, $this->getNumericStorageId())); $files = array(); while ($row = $result->fetchRow()) { - $row['mimetype'] = $this->getMimetype($row['mimetype']); - $row['mimepart'] = $this->getMimetype($row['mimepart']); + $row['mimetype'] = $this->mimetypeLoader->getMimetypeById($row['mimetype']); + $row['mimepart'] = $this->mimetypeLoader->getMimetypeById($row['mimepart']); $files[] = $row; } return $files; diff --git a/lib/private/files/type/loader.php b/lib/private/files/type/loader.php new file mode 100644 index 00000000000..df893306615 --- /dev/null +++ b/lib/private/files/type/loader.php @@ -0,0 +1,165 @@ +<?php +/** + * @author Robin McCorkell <rmccorkell@owncloud.com> + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OC\Files\Type; + +use OCP\Files\IMimeTypeLoader; +use OCP\IDBConnection; + +use Doctrine\DBAL\Exception\UniqueConstraintViolationException; + +/** + * Mimetype database loader + * + * @package OC\Files\Type + */ +class Loader implements IMimeTypeLoader { + + /** @var IDBConnection */ + private $dbConnection; + + /** @var array [id => mimetype] */ + protected $mimetypes; + + /** @var array [mimetype => id] */ + protected $mimetypeIds; + + /** + * @param IDBConnection $dbConnection + */ + public function __construct(IDBConnection $dbConnection) { + $this->dbConnection = $dbConnection; + $this->mimetypes = []; + $this->mimetypeIds = []; + } + + /** + * Get a mimetype from its ID + * + * @param int $id + * @return string|null + */ + public function getMimetypeById($id) { + if (!$this->mimetypes) { + $this->loadMimetypes(); + } + if (isset($this->mimetypes[$id])) { + return $this->mimetypes[$id]; + } + return null; + } + + /** + * Get a mimetype ID, adding the mimetype to the DB if it does not exist + * + * @param string $mimetype + * @return int + */ + public function getId($mimetype) { + if (!$this->mimetypeIds) { + $this->loadMimetypes(); + } + if (isset($this->mimetypeIds[$mimetype])) { + return $this->mimetypeIds[$mimetype]; + } + return $this->store($mimetype); + } + + /** + * Test if a mimetype exists in the database + * + * @param string $mimetype + * @return bool + */ + public function exists($mimetype) { + if (!$this->mimetypeIds) { + $this->loadMimetypes(); + } + return isset($this->mimetypeIds[$mimetype]); + } + + /** + * Store a mimetype in the DB + * + * @param string $mimetype + * @param int inserted ID + */ + protected function store($mimetype) { + try { + $qb = $this->dbConnection->getQueryBuilder(); + $qb->insert('mimetypes') + ->values([ + 'mimetype' => $qb->createNamedParameter($mimetype) + ]); + $qb->execute(); + } catch (UniqueConstraintViolationException $e) { + // something inserted it before us + } + + $fetch = $this->dbConnection->getQueryBuilder(); + $fetch->select('id') + ->from('mimetypes') + ->where( + $fetch->expr()->eq('mimetype', $fetch->createNamedParameter($mimetype) + )); + $row = $fetch->execute()->fetch(); + + $this->mimetypes[$row['id']] = $mimetype; + $this->mimetypeIds[$mimetype] = $row['id']; + return $row['id']; + } + + /** + * Load all mimetypes from DB + */ + private function loadMimetypes() { + $qb = $this->dbConnection->getQueryBuilder(); + $qb->select('id', 'mimetype') + ->from('mimetypes'); + $results = $qb->execute()->fetchAll(); + + foreach ($results as $row) { + $this->mimetypes[$row['id']] = $row['mimetype']; + $this->mimetypeIds[$row['mimetype']] = $row['id']; + } + } + + /** + * Update filecache mimetype based on file extension + * + * @param string $ext file extension + * @param int $mimetypeId + * @return int number of changed rows + */ + public function updateFilecache($ext, $mimetypeId) { + $update = $this->dbConnection->getQueryBuilder(); + $update->update('filecache') + ->set('mimetype', $update->createNamedParameter($mimetypeId)) + ->where($update->expr()->neq( + 'mimetype', $update->createNamedParameter($mimetypeId) + )) + ->andWhere($update->expr()->like( + $update->createFunction('LOWER(`name`)'), $update->createNamedParameter($ext) + )); + return $update->execute(); + } + +} diff --git a/lib/private/server.php b/lib/private/server.php index a741f33eb3d..f92c68f037c 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -470,6 +470,11 @@ class Server extends SimpleContainer implements IServerContainer { $c->getURLGenerator(), \OC::$configDir); }); + $this->registerService('MimeTypeLoader', function(Server $c) { + return new \OC\Files\Type\Loader( + $c->getDatabaseConnection() + ); + }); $this->registerService('CapabilitiesManager', function (Server $c) { $manager = new \OC\CapabilitiesManager(); $manager->registerCapability(function() use ($c) { @@ -1011,6 +1016,15 @@ class Server extends SimpleContainer implements IServerContainer { } /** + * Get the MimeTypeLoader + * + * @return \OCP\Files\IMimeTypeLoader + */ + public function getMimeTypeLoader() { + return $this->query('MimeTypeLoader'); + } + + /** * Get the manager of all the capabilities * * @return \OC\CapabilitiesManager diff --git a/lib/public/files/imimetypeloader.php b/lib/public/files/imimetypeloader.php new file mode 100644 index 00000000000..24937ea9b86 --- /dev/null +++ b/lib/public/files/imimetypeloader.php @@ -0,0 +1,59 @@ +<?php +/** + * @author Robin McCorkell <rmccorkell@owncloud.com> + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCP\Files; + +/** + * Interface IMimeTypeLoader + * @package OCP\Files + * @since 8.2.0 + * + * Interface to load mimetypes + **/ +interface IMimeTypeLoader { + + /** + * Get a mimetype from its ID + * + * @param int $id + * @return string|null + * @since 8.2.0 + */ + public function getMimetypeById($id); + + /** + * Get a mimetype ID, adding the mimetype to the DB if it does not exist + * + * @param string $mimetype + * @return int + * @since 8.2.0 + */ + public function getId($mimetype); + + /** + * Test if a mimetype exists in the database + * + * @param string $mimetype + * @return bool + * @since 8.2.0 + */ + public function exists($mimetype); +} diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index a6d83156de3..81724cb4967 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -440,6 +440,14 @@ interface IServerContainer { */ public function getMimeTypeDetector(); + /** + * Get the MimeTypeLoader + * + * @return \OCP\Files\IMimeTypeLoader + * @since 8.2.0 + */ + public function getMimeTypeLoader(); + /** * Get the EventDispatcher diff --git a/tests/lib/repair/repairmimetypes.php b/tests/lib/repair/repairmimetypes.php index 40ffc14612b..76d4d7cc656 100644 --- a/tests/lib/repair/repairmimetypes.php +++ b/tests/lib/repair/repairmimetypes.php @@ -22,8 +22,17 @@ class RepairMimeTypes extends \Test\TestCase { protected function setUp() { parent::setUp(); - $this->storage = new \OC\Files\Storage\Temporary([]); + $this->savedMimetypeLoader = \OC::$server->getMimeTypeLoader(); + $this->mimetypeLoader = $this->getMockBuilder('\OC\Files\Type\Loader') + ->setConstructorArgs([\OC::$server->getDatabaseConnection()]) + ->setMethods(null) + ->getMock(); + \OC::$server->registerService('MimeTypeLoader', function ($c) { + return $this->mimetypeLoader; + }); + + $this->storage = new \OC\Files\Storage\Temporary([]); $this->repair = new \OC\Repair\RepairMimeTypes(); } @@ -33,7 +42,9 @@ class RepairMimeTypes extends \Test\TestCase { \OC_DB::executeAudited($sql, [$this->storage->getId()]); $this->clearMimeTypes(); - DummyFileCache::clearCachedMimeTypes(); + \OC::$server->registerService('MimeTypeLoader', function($c) { + return $this->savedMimetypeLoader; + }); parent::tearDown(); } @@ -86,8 +97,7 @@ class RepairMimeTypes extends \Test\TestCase { $this->repair->run(); // force mimetype reload - DummyFileCache::clearCachedMimeTypes(); - $this->storage->getCache()->loadMimeTypes(); + self::invokePrivate($this->mimetypeLoader, 'loadMimetypes'); $this->checkEntries($fixedMimeTypes); } @@ -434,14 +444,3 @@ class RepairMimeTypes extends \Test\TestCase { } } -/** - * Dummy class to access protected members - */ -class DummyFileCache extends \OC\Files\Cache\Cache { - - public static function clearCachedMimeTypes() { - self::$mimetypeIds = []; - self::$mimetypes = []; - } -} - |