Skip to content

Commit

Permalink
Merge pull request #233 from humhub/fix/230-slow-files-from-stream
Browse files Browse the repository at this point in the history
Optimize sql query to get files from the stream
  • Loading branch information
luke- committed Sep 23, 2024
2 parents eef8f2a + c44209d commit 5313ad8
Show file tree
Hide file tree
Showing 16 changed files with 65 additions and 57 deletions.
4 changes: 2 additions & 2 deletions controllers/BaseController.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ public function beforeAction($action)
if (!$this->getRootFolder()) {
$this->_rootFolder = Folder::initRoot($this->contentContainer);
$newRoot = true;
} elseif($this->getRootFolder()->content->isPrivate()) {
} elseif ($this->getRootFolder()->content->isPrivate()) {
// Make sure older root folders are public by default.
$this->getRootFolder()->content->visibility = Content::VISIBILITY_PUBLIC;
$this->getRootFolder()->content->save();
}

if ($this->getAllPostedFilesFolder() == null) {
$this->_allPostedFilesFolder = Folder::initPostedFilesFolder($this->contentContainer);
} elseif($this->getAllPostedFilesFolder()->content->isPrivate()) {
} elseif ($this->getAllPostedFilesFolder()->content->isPrivate()) {
$this->getAllPostedFilesFolder()->content->visibility = Content::VISIBILITY_PUBLIC;
$this->getAllPostedFilesFolder()->content->save();
}
Expand Down
2 changes: 1 addition & 1 deletion controllers/BrowseController.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class BrowseController extends BaseController
public function actionIndex()
{
$currentFolder = $this->getCurrentFolder();
if(!$currentFolder->content->canView()) {
if (!$currentFolder->content->canView()) {
throw new HttpException(403);
}

Expand Down
2 changes: 1 addition & 1 deletion controllers/DeleteController.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public function actionIndex()
foreach ($selectedItems as $itemId) {
$item = FileSystemItem::getItemById($itemId);

if(!$item->content->canEdit()) {
if (!$item->content->canEdit()) {
throw new HttpException(403);
}

Expand Down
2 changes: 1 addition & 1 deletion controllers/EditController.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ private function updateVisibility(SelectionForm $model, $visibility)
foreach ($model->selection as $itemId) {
$item = FileSystemItem::getItemById($itemId);

if(!$item->content->canEdit()) {
if (!$item->content->canEdit()) {
throw new HttpException(403);
}

Expand Down
2 changes: 1 addition & 1 deletion controllers/MoveController.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public function actionIndex() //Make sure an $fid is given otherwise the root fo
]);
}

if($model->save()) {
if ($model->save()) {
$this->view->saved();
return $this->htmlRedirect($model->destination->createUrl('/cfiles/browse'));
} else {
Expand Down
2 changes: 1 addition & 1 deletion controllers/rest/FileController.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public function actionUpload($containerId)
foreach ($files as $file) {
$file = $targetDir->addUploadedFile($file);

if($file->hasErrors() || $file->baseFile->hasErrors()) {
if ($file->hasErrors() || $file->baseFile->hasErrors()) {
return $this->returnError(422, "File {$file->baseFile->name} could not be uploaded!", [
'errors' => array_merge($file->getErrors(), $file->baseFile->getErrors()),
]);
Expand Down
8 changes: 4 additions & 4 deletions controllers/rest/ManageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public function actionDelete($containerId)
}

foreach ($result as $item) {
if(! $item->delete()) {
if (! $item->delete()) {
Yii::error('Could not delete cFiles items.', 'api');
return $this->returnError(500, 'Internal error while deleting cFiles item!');
}
Expand Down Expand Up @@ -81,7 +81,7 @@ public function actionMove($containerId)
]);
}

if($model->load($params) && $model->save()) {
if ($model->load($params) && $model->save()) {
return $this->returnSuccess('Items successfully moved.');
}

Expand Down Expand Up @@ -115,7 +115,7 @@ public function actionMakePublic($containerId)

foreach ($result as $item) {
$item->updateVisibility(Content::VISIBILITY_PUBLIC);
if(! $item->content->save()) {
if (! $item->content->save()) {
Yii::error('Could not set public visibility for cFiles items.', 'api');
return $this->returnError(500, 'Internal error while setting public visibility for cFiles item!');
}
Expand Down Expand Up @@ -144,7 +144,7 @@ public function actionMakePrivate($containerId)

foreach ($result as $item) {
$item->updateVisibility(Content::VISIBILITY_PRIVATE);
if(! $item->content->save()) {
if (! $item->content->save()) {
Yii::error('Could not set private visibility for cFiles items.', 'api');
return $this->returnError(500, 'Internal error while setting private visibility for cFiles item!');
}
Expand Down
1 change: 1 addition & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Changelog
- Enh #224: Unifying positions of button on modals for consistency and better UX
- Enh #227: Use PHP CS Fixer
- Fix: Add autofocus on file or folder edit (for HumHub 1.17 - see https://github.com/humhub/humhub/issues/7136)
- Fix #230: Optimize sql query to get files from the stream

0.16.6 - March 14, 2024
-------------------------
Expand Down
8 changes: 4 additions & 4 deletions libs/ZipExtractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ protected function generateModelsFromFilesystem(Folder $targetFolder, $folderPat
// remove unwanted parent folder references from the scanned files
$files = array_diff(scandir($folderPath), ['..','.']);

if(!$root) {
if (!$root) {
$root = $targetFolder;
}

Expand All @@ -81,9 +81,9 @@ protected function generateModelsFromFilesystem(Folder $targetFolder, $folderPat
if (is_dir($filePath)) {
$folder = $targetFolder->findFolderByName($file);

if(!$folder) {
if (!$folder) {
$folder = $targetFolder->newFolder($file);
if(!$folder->save()) {
if (!$folder->save()) {
$root->addError('upload', Yii::t('CfilesModule.base', 'An error occurred while creating folder {folder}.', ['folder' => $file]));
continue;
}
Expand All @@ -92,7 +92,7 @@ protected function generateModelsFromFilesystem(Folder $targetFolder, $folderPat
$this->generateModelsFromFilesystem($folder, $filePath, $root);
} else {
$result = $this->generateModelFromFile($targetFolder, $folderPath, $file);
if($result->hasErrors()) {
if ($result->hasErrors()) {
$root->addError('upload', Yii::t('CfilesModule.base', 'An error occurred while unpacking {filename}.', ['filename' => $file]));
}
}
Expand Down
8 changes: 4 additions & 4 deletions migrations/m150720_174011_initial.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ class m150720_174011_initial extends Migration
{
public function up()
{
$this->createTable('cfiles_file', array(
$this->createTable('cfiles_file', [
'id' => 'pk',
'parent_folder_id' => 'int(11) NULL',
), '');
], '');

$this->createTable('cfiles_folder', array(
$this->createTable('cfiles_folder', [
'id' => 'pk',
'parent_folder_id' => 'int(11) NULL',
'title' => 'varchar(255) NOT NULL',
), '');
], '');
}

public function down()
Expand Down
2 changes: 1 addition & 1 deletion migrations/m170830_122439_foreignkeys.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public function safeUp()
try {
$this->addForeignKey('fk_cfiles_file_parent_folder', 'cfiles_file', 'parent_folder_id', 'cfiles_folder', 'id', 'SET NULL');
$this->addForeignKey('fk_cfiles_folder_parent_folder', 'cfiles_folder', 'parent_folder_id', 'cfiles_folder', 'id', 'SET NULL');
} catch(Exception $e) {
} catch (Exception $e) {
Yii::error($e);
}
}
Expand Down
63 changes: 35 additions & 28 deletions models/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use humhub\modules\file\libs\FileHelper;
use humhub\modules\file\models\File as BaseFile;
use humhub\modules\file\models\FileUpload;
use humhub\modules\post\models\Post;
use humhub\modules\search\events\SearchAddEvent;
use humhub\modules\topic\models\Topic;
use humhub\modules\user\models\User;
Expand Down Expand Up @@ -96,7 +97,7 @@ public function rules()
['hidden', 'boolean'],
];

if($this->parentFolder && $this->parentFolder->content->isPublic()) {
if ($this->parentFolder && $this->parentFolder->content->isPublic()) {
$rules[] = ['visibility', 'integer', 'min' => 0, 'max' => 1];
}

Expand All @@ -123,11 +124,11 @@ public function getSearchAttributes()
'description' => $this->description,
];

if($this->getCreator()) {
if ($this->getCreator()) {
$attributes['creator'] = $this->getCreator()->getDisplayName();
}

if($this->getEditor()) {
if ($this->getEditor()) {
$attributes['editor'] = $this->getEditor()->getDisplayName();
}

Expand Down Expand Up @@ -205,16 +206,16 @@ public function updateVisibility($visibility)
return;
}

if(!$this->parentFolder->content->isPrivate() || $visibility == Content::VISIBILITY_PRIVATE) {
if (!$this->parentFolder->content->isPrivate() || $visibility == Content::VISIBILITY_PRIVATE) {
// For user profile files we use Content::VISIBILITY_OWNER isntead of private
$this->content->visibility = $visibility;
}
}

public function getVisibilityTitle()
{
if(Yii::$app->getModule('friendship')->settings->get('enable') && $this->content->container instanceof User) {
if($this->content->container->isCurrentuser()) {
if (Yii::$app->getModule('friendship')->settings->get('enable') && $this->content->container instanceof User) {
if ($this->content->container->isCurrentuser()) {
$privateText = Yii::t('CfilesModule.base', 'This file is only visible for you and your friends.');
} else {
$privateText = Yii::t('CfilesModule.base', 'This file is protected.');
Expand Down Expand Up @@ -323,7 +324,7 @@ public function getEditUrl()
/**
* Get the post related to the given file file.
*/
public static function getBasePost(\humhub\modules\file\models\File $file = null)
public static function getBasePost(BaseFile $file = null)
{
if ($file === null) {
return null;
Expand Down Expand Up @@ -386,31 +387,37 @@ public function getFullPath($separator = '/')
*/
public static function getPostedFiles($contentContainer, $filesOrder = ['file.updated_at' => SORT_ASC, 'file.title' => SORT_ASC])
{
// Get Posted Files
$query = \humhub\modules\file\models\File::find();
// join comments to the file if available
$query->join('LEFT JOIN', 'comment', '(file.object_id=comment.id AND file.object_model=' . Yii::$app->db->quoteValue(Comment::className()) . ')');
// join parent post of comment or file
$query->join('LEFT JOIN', 'content', '(comment.object_model=content.object_model AND comment.object_id=content.object_id) OR (file.object_model=content.object_model AND file.object_id=content.object_id)');
// only accept Posts as the base content, so stuff from sumbmodules like files itsself or gallery will be excluded

$query->andWhere(['content.contentcontainer_id' => $contentContainer->contentContainerRecord->id]);
// Initialise sub queries to get files from Posts and Comments
$subQueries = [
Post::class => Content::find()
->select('content.object_id')
->where(['content.object_model' => Post::class]),
Comment::class => Content::find()
->select('comment.id')
->innerJoin('comment', 'comment.object_model = content.object_model AND comment.object_id = content.object_id')
->where(['comment.object_model' => Post::class]),
];

if(!$contentContainer->canAccessPrivateContent()) {
// Note this will cut comment images, but including the visibility of comments is pretty complex...
$query->andWhere(['content.visibility' => Content::VISIBILITY_PUBLIC]);
}
$query = BaseFile::find();

$query->andWhere(['content.state' => Content::STATE_PUBLISHED]);
foreach ($subQueries as $objectClass => $subQuery) {
// Filter Content records by container and visibility states
$subQuery->andWhere(['content.contentcontainer_id' => $contentContainer->contentContainerRecord->id])
->andWhere(['content.state' => Content::STATE_PUBLISHED]);
if (!$contentContainer->canAccessPrivateContent()) {
// Note this will cut comment images, but including the visibility of comments is pretty complex...
$subQuery->andWhere(['content.visibility' => Content::VISIBILITY_PUBLIC]);
}

$query->orWhere([
'AND',
['file.object_model' => $objectClass],
['IN', 'file.object_id', $subQuery],
]);
}

// only accept Posts as the base content, so stuff from sumbmodules like files itsself or gallery will be excluded
$query->andWhere(
['or',
['=', 'comment.object_model', \humhub\modules\post\models\Post::className()],
['=', 'file.object_model', \humhub\modules\post\models\Post::className()],
],
);

// Get Files from comments
return $query->orderBy($filesOrder);
}

Expand Down
4 changes: 2 additions & 2 deletions models/Folder.php
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,11 @@ public function getSearchAttributes()
'description' => $this->description,
];

if($this->getCreator()) {
if ($this->getCreator()) {
$attributes['creator'] = $this->getCreator()->getDisplayName();
}

if($this->getEditor()) {
if ($this->getEditor()) {
$attributes['editor'] = $this->getEditor()->getDisplayName();
}
}
Expand Down
6 changes: 3 additions & 3 deletions models/rows/AbstractFileSystemItemRow.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public static function translateOrder($sort = null, $order = 'ASC')
{
$result = static::DEFAULT_ORDER;

if($sort && array_key_exists($sort, static::ORDER_MAPPING)) {
if ($sort && array_key_exists($sort, static::ORDER_MAPPING)) {
$result = static::ORDER_MAPPING[$sort] ? static::ORDER_MAPPING[$sort] . ' ' . $order : $result;
}

Expand All @@ -108,11 +108,11 @@ public static function translateOrder($sort = null, $order = 'ASC')
*/
public function isRenderColumn($column)
{
if($column === self::COLUMN_SELECT && !$this->showSelect) {
if ($column === self::COLUMN_SELECT && !$this->showSelect) {
return false;
}

if(!$this->_columns) {
if (!$this->_columns) {
$this->_columns = $this->getColumns();
}

Expand Down
2 changes: 1 addition & 1 deletion tests/codeception/_support/AcceptanceTester.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public function createFolder($title = 'test', $description = 'test description',
$this->fillField('Folder[title]', $title);
$this->fillField('Folder[description]', $description);

if($isPublic) {
if ($isPublic) {
$this->jsClick('input#folder-visibility');
}

Expand Down
6 changes: 3 additions & 3 deletions widgets/FileList.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ public function initSort()
$this->order = Yii::$app->request->get('order', $this->order);

// Save sort settings if sorting was used and logged in user is given or try fetching user settings.
if(Yii::$app->request->get('sort') && !Yii::$app->user->isGuest) {
if (Yii::$app->request->get('sort') && !Yii::$app->user->isGuest) {
$settings = $module->settings->user(Yii::$app->user->getIdentity());
$settings->set('defaultSort', $this->sort);
$settings->set('defaultOrder', $this->order);
} elseif(!Yii::$app->user->isGuest) {
} elseif (!Yii::$app->user->isGuest) {
$settings = $module->settings->user(Yii::$app->user->getIdentity());
$this->sort = $settings->get('defaultSort', $this->sort);
$this->order = $settings->get('defaultOrder', $this->order);
Expand Down Expand Up @@ -115,7 +115,7 @@ public function getDefaultOrder()
*/
public function run()
{
if($this->folder->isAllPostedFiles()) {
if ($this->folder->isAllPostedFiles()) {
$this->setPostedFilesRows();
} else {
$this->setSystemItemRows();
Expand Down

0 comments on commit 5313ad8

Please sign in to comment.