Changed file mgmt to use entities' lazy getters
This commit is contained in:
parent
a2587fb0d8
commit
a3f9382671
18 changed files with 426 additions and 96 deletions
13
TODO
13
TODO
|
@ -8,6 +8,10 @@ everything related to posts:
|
|||
- comment count
|
||||
- fix broken thumbnails if no external software is installed
|
||||
|
||||
- uploading post
|
||||
- remove hard dependency on gd2 in PostService::setContentFromString
|
||||
(getimagesizefromstring)
|
||||
|
||||
- single post view
|
||||
- post content
|
||||
- post tags
|
||||
|
@ -124,17 +128,10 @@ refactors:
|
|||
separate PostTagDao for this)
|
||||
- post view proxy should retrieve full tags and full user
|
||||
- centralize markdown prefix decorators
|
||||
- move getPostContentPath i getAvatarSourcePath to Entity, include it in
|
||||
- move getPostContentPath and getAvatarSourcePath to Entity, include it in
|
||||
ViewProxy and make presenters use it instead of duplicating the code
|
||||
- after implementing Post::getPostContentPath, make paths include file
|
||||
extensions so that apache can guess mime types when it serves the files
|
||||
- add afterSave, afterDelete in Dao layer
|
||||
- refactor to file content management
|
||||
- move fileService dependency to Dao layer
|
||||
- move setContent i getContent to entities
|
||||
- add afterSave that talks to fileService to save the content
|
||||
- inside afterLoad inject method wchi talks to fileService to read the
|
||||
content
|
||||
- add enum validation in IValidatables (needs refactors of enums and
|
||||
possible disposal of EnumHelper in favor of something more subtle)
|
||||
- (idea) keep denormalized data in separate tables, i.e. tag usages in
|
||||
|
|
|
@ -29,16 +29,16 @@ final class PostContentController extends AbstractController
|
|||
public function getPostContent($postName)
|
||||
{
|
||||
$post = $this->postService->getByName($postName);
|
||||
$source = $this->postService->getPostContentPath($post);
|
||||
$source = $post->getContentPath();
|
||||
$this->fileService->serve($source);
|
||||
}
|
||||
|
||||
public function getPostThumbnail($postName, $size)
|
||||
{
|
||||
$post = $this->postService->getByName($postName);
|
||||
$source = $this->postService->getPostThumbnailSourcePath($post);
|
||||
$source = $post->getThumbnailSourceContentPath();
|
||||
if (!$this->fileService->exists($source))
|
||||
$source = $this->postService->getPostContentPath($post);
|
||||
$source = $post->getContentPath();
|
||||
|
||||
$sizedSource = $this->thumbnailService->getOrGenerate($source, $size, $size);
|
||||
$this->fileService->serve($sizedSource);
|
||||
|
|
|
@ -38,15 +38,15 @@ final class UserAvatarController extends AbstractController
|
|||
break;
|
||||
|
||||
case \Szurubooru\Entities\User::AVATAR_STYLE_BLANK:
|
||||
$this->serveFromFile($this->userService->getBlankAvatarSourcePath(), $size);
|
||||
$this->serveFromFile($this->getBlankAvatarSourcePath(), $size);
|
||||
break;
|
||||
|
||||
case \Szurubooru\Entities\User::AVATAR_STYLE_MANUAL:
|
||||
$this->serveFromFile($this->userService->getCustomAvatarSourcePath($user), $size);
|
||||
$this->serveFromFile($user->getCustomAvatarSourceContentPath(), $size);
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->serveFromFile($this->userService->getBlankAvatarSourcePath(), $size);
|
||||
$this->serveFromFile($this->getBlankAvatarSourcePath(), $size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -59,9 +59,14 @@ final class UserAvatarController extends AbstractController
|
|||
private function serveFromFile($file, $size)
|
||||
{
|
||||
if (!$this->fileService->exists($file))
|
||||
$file = $this->userService->getBlankAvatarSourcePath();
|
||||
$file = $this->getBlankAvatarSourcePath();
|
||||
|
||||
$sizedFile = $this->thumbnailService->getOrGenerate($file, $size, $size);
|
||||
$this->fileService->serve($sizedFile);
|
||||
}
|
||||
|
||||
private function getBlankAvatarSourcePath()
|
||||
{
|
||||
return 'avatars' . DIRECTORY_SEPARATOR . 'blank.png';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,6 +66,10 @@ abstract class AbstractDao implements ICrudDao
|
|||
|
||||
public function deleteAll()
|
||||
{
|
||||
foreach ($this->findAll() as $entity)
|
||||
{
|
||||
$this->beforeDelete($entity);
|
||||
}
|
||||
$this->fpdo->deleteFrom($this->tableName)->execute();
|
||||
}
|
||||
|
||||
|
@ -94,17 +98,32 @@ abstract class AbstractDao implements ICrudDao
|
|||
return count(iterator_to_array($this->fpdo->from($this->tableName)->limit(1))) > 0;
|
||||
}
|
||||
|
||||
protected function findBy($columnName, $value)
|
||||
{
|
||||
$entities = [];
|
||||
$query = $this->fpdo->from($this->tableName)->where($columnName, $value);
|
||||
foreach ($query as $arrayEntity)
|
||||
{
|
||||
$entity = $this->entityConverter->toEntity($arrayEntity);
|
||||
$entities[$entity->getId()] = $entity;
|
||||
}
|
||||
return $entities;
|
||||
}
|
||||
|
||||
protected function findOneBy($columnName, $value)
|
||||
{
|
||||
$arrayEntity = iterator_to_array($this->fpdo->from($this->tableName)->where($columnName, $value));
|
||||
if (!$arrayEntity)
|
||||
$arrayEntities = $this->findBy($columnName, $value);
|
||||
if (!$arrayEntities)
|
||||
return null;
|
||||
|
||||
return $this->entityConverter->toEntity($arrayEntity[0]);
|
||||
return array_shift($arrayEntities);
|
||||
}
|
||||
|
||||
protected function deleteBy($columnName, $value)
|
||||
{
|
||||
foreach ($this->findBy($columnName, $value) as $entity)
|
||||
{
|
||||
$this->beforeDelete($entity);
|
||||
}
|
||||
$this->fpdo->deleteFrom($this->tableName)->where($columnName, $value)->execute();
|
||||
}
|
||||
|
||||
|
@ -115,4 +134,8 @@ abstract class AbstractDao implements ICrudDao
|
|||
protected function afterSave(\Szurubooru\Entities\Entity $entity)
|
||||
{
|
||||
}
|
||||
|
||||
protected function beforeDelete(\Szurubooru\Entities\Entity $entity)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,21 @@ namespace Szurubooru\Dao;
|
|||
|
||||
class PostDao extends AbstractDao implements ICrudDao
|
||||
{
|
||||
public function __construct(\Szurubooru\DatabaseConnection $databaseConnection)
|
||||
private $fileService;
|
||||
private $thumbnailService;
|
||||
|
||||
public function __construct(
|
||||
\Szurubooru\DatabaseConnection $databaseConnection,
|
||||
\Szurubooru\Services\FileService $fileService,
|
||||
\Szurubooru\Services\ThumbnailService $thumbnailService)
|
||||
{
|
||||
parent::__construct(
|
||||
$databaseConnection,
|
||||
'posts',
|
||||
new \Szurubooru\Dao\EntityConverters\PostEntityConverter());
|
||||
|
||||
$this->fileService = $fileService;
|
||||
$this->thumbnailService = $thumbnailService;
|
||||
}
|
||||
|
||||
public function findByName($name)
|
||||
|
@ -21,17 +30,35 @@ class PostDao extends AbstractDao implements ICrudDao
|
|||
return $this->findOneBy('contentChecksum', $checksum);
|
||||
}
|
||||
|
||||
protected function afterLoad(\Szurubooru\Entities\Entity $entity)
|
||||
protected function afterLoad(\Szurubooru\Entities\Entity $post)
|
||||
{
|
||||
$entity->setLazyLoader('tags', function(\Szurubooru\Entities\Post $post)
|
||||
$post->setLazyLoader(
|
||||
\Szurubooru\Entities\Post::LAZY_LOADER_CONTENT,
|
||||
function(\Szurubooru\Entities\Post $post)
|
||||
{
|
||||
return $this->fileService->load($post->getContentPath());
|
||||
});
|
||||
|
||||
$post->setLazyLoader(
|
||||
\Szurubooru\Entities\Post::LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT,
|
||||
function(\Szurubooru\Entities\Post $post)
|
||||
{
|
||||
return $this->fileService->load($post->getThumbnailSourceContentPath());
|
||||
});
|
||||
|
||||
$post->setLazyLoader(
|
||||
\Szurubooru\Entities\Post::LAZY_LOADER_TAGS,
|
||||
function(\Szurubooru\Entities\Post $post)
|
||||
{
|
||||
return $this->getTags($post);
|
||||
});
|
||||
}
|
||||
|
||||
protected function afterSave(\Szurubooru\Entities\Entity $entity)
|
||||
protected function afterSave(\Szurubooru\Entities\Entity $post)
|
||||
{
|
||||
$this->syncTags($entity->getId(), $entity->getTags());
|
||||
$this->syncContent($post);
|
||||
$this->syncThumbnailSourceContent($post);
|
||||
$this->syncTags($post->getId(), $post->getTags());
|
||||
}
|
||||
|
||||
private function getTags(\Szurubooru\Entities\Post $post)
|
||||
|
@ -44,6 +71,28 @@ class PostDao extends AbstractDao implements ICrudDao
|
|||
return $result;
|
||||
}
|
||||
|
||||
private function syncContent(\Szurubooru\Entities\Post $post)
|
||||
{
|
||||
$targetPath = $post->getContentPath();
|
||||
$content = $post->getContent();
|
||||
if ($content)
|
||||
$this->fileService->save($targetPath, $content);
|
||||
else
|
||||
$this->fileService->delete($targetPath, $content);
|
||||
$this->thumbnailService->deleteUsedThumbnails($targetPath);
|
||||
}
|
||||
|
||||
private function syncThumbnailSourceContent(\Szurubooru\Entities\Post $post)
|
||||
{
|
||||
$targetPath = $post->getThumbnailSourceContentPath();
|
||||
$content = $post->getThumbnailSourceContent();
|
||||
if ($content)
|
||||
$this->fileService->save($targetPath, $content);
|
||||
else
|
||||
$this->fileService->delete($targetPath);
|
||||
$this->thumbnailService->deleteUsedThumbnails($targetPath);
|
||||
}
|
||||
|
||||
private function syncTags($postId, array $tags)
|
||||
{
|
||||
$existingTags = array_map(
|
||||
|
|
|
@ -3,12 +3,21 @@ namespace Szurubooru\Dao;
|
|||
|
||||
class UserDao extends AbstractDao implements ICrudDao
|
||||
{
|
||||
public function __construct(\Szurubooru\DatabaseConnection $databaseConnection)
|
||||
private $fileService;
|
||||
private $thumbnailService;
|
||||
|
||||
public function __construct(
|
||||
\Szurubooru\DatabaseConnection $databaseConnection,
|
||||
\Szurubooru\Services\FileService $fileService,
|
||||
\Szurubooru\Services\ThumbnailService $thumbnailService)
|
||||
{
|
||||
parent::__construct(
|
||||
$databaseConnection,
|
||||
'users',
|
||||
new \Szurubooru\Dao\EntityConverters\UserEntityConverter());
|
||||
|
||||
$this->fileService = $fileService;
|
||||
$this->thumbnailService = $thumbnailService;
|
||||
}
|
||||
|
||||
public function findByName($userName)
|
||||
|
@ -36,4 +45,33 @@ class UserDao extends AbstractDao implements ICrudDao
|
|||
$this->deleteBy('name', $userName);
|
||||
$this->fpdo->deleteFrom('tokens')->where('additionalData', $userName);
|
||||
}
|
||||
|
||||
protected function afterLoad(\Szurubooru\Entities\Entity $user)
|
||||
{
|
||||
$user->setLazyLoader(
|
||||
\Szurubooru\Entities\User::LAZY_LOADER_CUSTOM_AVATAR_SOURCE_CONTENT,
|
||||
function(\Szurubooru\Entities\User $user)
|
||||
{
|
||||
$avatarSource = $user->getCustomAvatarSourceContentPath();
|
||||
return $this->fileService->load($avatarSource);
|
||||
});
|
||||
}
|
||||
|
||||
protected function afterSave(\Szurubooru\Entities\Entity $user)
|
||||
{
|
||||
$targetPath = $user->getCustomAvatarSourceContentPath();
|
||||
$content = $user->getCustomAvatarSourceContent();
|
||||
if ($content)
|
||||
$this->fileService->save($targetPath, $content);
|
||||
else
|
||||
$this->fileService->delete($targetPath);
|
||||
$this->thumbnailService->deleteUsedThumbnails($targetPath);
|
||||
}
|
||||
|
||||
protected function afterDelete(\Szurubooru\Entities\Entity $user)
|
||||
{
|
||||
$avatarSource = $user->getCustomAvatarSourceContentPath();
|
||||
$this->fileService->delete($avatarSource);
|
||||
$this->thumbnailService->deleteUsedThumbnails($avatarSource);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,10 @@ final class Post extends Entity
|
|||
const POST_TYPE_VIDEO = 3;
|
||||
const POST_TYPE_YOUTUBE = 4;
|
||||
|
||||
const LAZY_LOADER_TAGS = 'tags';
|
||||
const LAZY_LOADER_CONTENT = 'content';
|
||||
const LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT = 'thumbnailSourceContent';
|
||||
|
||||
protected $name;
|
||||
protected $userId;
|
||||
protected $uploadTime;
|
||||
|
@ -175,11 +179,41 @@ final class Post extends Entity
|
|||
|
||||
public function getTags()
|
||||
{
|
||||
return $this->lazyLoad('tags', []);
|
||||
return $this->lazyLoad(self::LAZY_LOADER_TAGS, []);
|
||||
}
|
||||
|
||||
public function setTags(array $tags)
|
||||
{
|
||||
$this->lazySave('tags', $tags);
|
||||
$this->lazySave(self::LAZY_LOADER_TAGS, $tags);
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
return $this->lazyLoad(self::LAZY_LOADER_CONTENT, null);
|
||||
}
|
||||
|
||||
public function setContent($content)
|
||||
{
|
||||
$this->lazySave(self::LAZY_LOADER_CONTENT, $content);
|
||||
}
|
||||
|
||||
public function getThumbnailSourceContent()
|
||||
{
|
||||
return $this->lazyLoad(self::LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT, null);
|
||||
}
|
||||
|
||||
public function setThumbnailSourceContent($content)
|
||||
{
|
||||
$this->lazySave(self::LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT, $content);
|
||||
}
|
||||
|
||||
public function getContentPath()
|
||||
{
|
||||
return 'posts' . DIRECTORY_SEPARATOR . $this->getName();
|
||||
}
|
||||
|
||||
public function getThumbnailSourceContentPath()
|
||||
{
|
||||
return 'posts' . DIRECTORY_SEPARATOR . $this->getName() . '-custom-thumb';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ final class User extends Entity
|
|||
const AVATAR_STYLE_MANUAL = 2;
|
||||
const AVATAR_STYLE_BLANK = 3;
|
||||
|
||||
const LAZY_LOADER_CUSTOM_AVATAR_SOURCE_CONTENT = 'customAvatarContent';
|
||||
|
||||
protected $name;
|
||||
protected $email;
|
||||
protected $emailUnconfirmed;
|
||||
|
@ -124,4 +126,19 @@ final class User extends Entity
|
|||
{
|
||||
$this->browsingSettings = $browsingSettings;
|
||||
}
|
||||
|
||||
public function getCustomAvatarSourceContent()
|
||||
{
|
||||
return $this->lazyLoad(self::LAZY_LOADER_CUSTOM_AVATAR_SOURCE_CONTENT, null);
|
||||
}
|
||||
|
||||
public function setCustomAvatarSourceContent($content)
|
||||
{
|
||||
$this->lazySave(self::LAZY_LOADER_CUSTOM_AVATAR_SOURCE_CONTENT, $content);
|
||||
}
|
||||
|
||||
public function getCustomAvatarSourceContentPath()
|
||||
{
|
||||
return 'avatars' . DIRECTORY_SEPARATOR . $this->getId();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@ final class InputReader extends \ArrayObject
|
|||
|
||||
public function decodeBase64($base64string)
|
||||
{
|
||||
if ($base64string === null)
|
||||
return null;
|
||||
$commaPosition = strpos($base64string, ',');
|
||||
if ($commaPosition !== null)
|
||||
$base64string = substr($base64string, $commaPosition + 1);
|
||||
|
|
|
@ -79,6 +79,14 @@ class FileService
|
|||
unlink($fullPath);
|
||||
}
|
||||
|
||||
public function load($source)
|
||||
{
|
||||
if (!$this->exists($source))
|
||||
return null;
|
||||
$fullPath = $this->getFullPath($source);
|
||||
return file_get_contents($fullPath);
|
||||
}
|
||||
|
||||
public function save($destination, $data)
|
||||
{
|
||||
$this->createFolders($destination);
|
||||
|
|
|
@ -8,9 +8,9 @@ class PostService
|
|||
private $transactionManager;
|
||||
private $postDao;
|
||||
private $postSearchService;
|
||||
private $fileService;
|
||||
private $timeService;
|
||||
private $authService;
|
||||
private $fileService;
|
||||
|
||||
public function __construct(
|
||||
\Szurubooru\Config $config,
|
||||
|
@ -27,9 +27,9 @@ class PostService
|
|||
$this->transactionManager = $transactionManager;
|
||||
$this->postDao = $postDao;
|
||||
$this->postSearchService = $postSearchService;
|
||||
$this->fileService = $fileService;
|
||||
$this->timeService = $timeService;
|
||||
$this->authService = $authService;
|
||||
$this->fileService = $fileService;
|
||||
}
|
||||
|
||||
public function getByNameOrId($postNameOrId)
|
||||
|
@ -92,16 +92,6 @@ class PostService
|
|||
return $this->transactionManager->commit($transactionFunc);
|
||||
}
|
||||
|
||||
public function getPostContentPath(\Szurubooru\Entities\Post $post)
|
||||
{
|
||||
return 'posts' . DIRECTORY_SEPARATOR . $post->getName();
|
||||
}
|
||||
|
||||
public function getPostThumbnailSourcePath(\Szurubooru\Entities\Post $post)
|
||||
{
|
||||
return 'posts' . DIRECTORY_SEPARATOR . $post->getName() . '-custom-thumb';
|
||||
}
|
||||
|
||||
private function updatePostSafety(\Szurubooru\Entities\Post $post, $newSafety)
|
||||
{
|
||||
$post->setSafety($newSafety);
|
||||
|
@ -145,15 +135,13 @@ class PostService
|
|||
$post->setContentChecksum(sha1($content));
|
||||
$this->assertNoPostWithThisContentChecksum($post);
|
||||
|
||||
$target = $this->getPostContentPath($post);
|
||||
$this->fileService->save($target, $content);
|
||||
$fullPath = $this->fileService->getFullPath($target);
|
||||
$post->setContent($content);
|
||||
|
||||
list ($imageWidth, $imageHeight) = getimagesize($fullPath);
|
||||
list ($imageWidth, $imageHeight) = getimagesizefromstring($content);
|
||||
$post->setImageWidth($imageWidth);
|
||||
$post->setImageHeight($imageHeight);
|
||||
|
||||
$post->setOriginalFileSize(filesize($fullPath));
|
||||
$post->setOriginalFileSize(strlen($content));
|
||||
}
|
||||
|
||||
private function updatePostContentFromUrl(\Szurubooru\Entities\Post $post, $url)
|
||||
|
@ -178,7 +166,7 @@ class PostService
|
|||
$this->assertNoPostWithThisContentChecksum($post);
|
||||
$youtubeThumbnailUrl = 'http://img.youtube.com/vi/' . $youtubeId . '/mqdefault.jpg';
|
||||
$youtubeThumbnail = $this->fileService->download($youtubeThumbnailUrl);
|
||||
$this->fileService->save($this->getPostThumbnailSourcePath($post), $youtubeThumbnail);
|
||||
$post->setThumbnailSourceContent($youtubeThumbnail);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -152,10 +152,6 @@ class UserService
|
|||
$transactionFunc = function() use ($user)
|
||||
{
|
||||
$this->userDao->deleteById($user->getId());
|
||||
|
||||
$avatarSource = $this->getCustomAvatarSourcePath($user);
|
||||
$this->fileService->delete($avatarSource);
|
||||
$this->thumbnailService->deleteUsedThumbnails($avatarSource);
|
||||
};
|
||||
$this->transactionManager->commit($transactionFunc);
|
||||
}
|
||||
|
@ -212,16 +208,6 @@ class UserService
|
|||
$this->transactionManager->commit($transactionFunc);
|
||||
}
|
||||
|
||||
public function getCustomAvatarSourcePath(\Szurubooru\Entities\User $user)
|
||||
{
|
||||
return 'avatars' . DIRECTORY_SEPARATOR . $user->getId();
|
||||
}
|
||||
|
||||
public function getBlankAvatarSourcePath()
|
||||
{
|
||||
return 'avatars' . DIRECTORY_SEPARATOR . 'blank.png';
|
||||
}
|
||||
|
||||
private function updateUserAvatarStyle(\Szurubooru\Entities\User $user, $newAvatarStyle)
|
||||
{
|
||||
$user->setAvatarStyle($newAvatarStyle);
|
||||
|
@ -229,9 +215,7 @@ class UserService
|
|||
|
||||
private function updateUserAvatarContent(\Szurubooru\Entities\User $user, $newAvatarContent)
|
||||
{
|
||||
$target = $this->getCustomAvatarSourcePath($user);
|
||||
$this->fileService->save($target, $newAvatarContent);
|
||||
$this->thumbnailService->deleteUsedThumbnails($target);
|
||||
$user->setCustomAvatarSourceContent($newAvatarContent);
|
||||
}
|
||||
|
||||
private function updateUserName(\Szurubooru\Entities\User $user, $newName)
|
||||
|
|
|
@ -5,20 +5,27 @@ class Upgrade04 implements IUpgrade
|
|||
{
|
||||
private $postService;
|
||||
private $fileService;
|
||||
private $thumbnailService;
|
||||
|
||||
public function __construct(
|
||||
\Szurubooru\Services\PostService $postService,
|
||||
\Szurubooru\Services\FileService $fileService)
|
||||
\Szurubooru\Services\FileService $fileService,
|
||||
\Szurubooru\Services\ThumbnailService $thumbnailService)
|
||||
{
|
||||
$this->postService = $postService;
|
||||
$this->fileService = $fileService;
|
||||
$this->thumbnailService = $thumbnailService;
|
||||
}
|
||||
|
||||
public function run(\Szurubooru\DatabaseConnection $databaseConnection)
|
||||
{
|
||||
$databaseConnection->getPDO()->exec('ALTER TABLE "posts" ADD COLUMN contentMimeType TEXT DEFAULT NULL');
|
||||
|
||||
$postDao = new \Szurubooru\Dao\PostDao($databaseConnection);
|
||||
$postDao = new \Szurubooru\Dao\PostDao(
|
||||
$databaseConnection,
|
||||
$this->fileService,
|
||||
$this->thumbnailService);
|
||||
|
||||
$posts = $postDao->findAll();
|
||||
foreach ($posts as $post)
|
||||
{
|
||||
|
|
|
@ -3,6 +3,16 @@ namespace Szurubooru\Tests\Dao;
|
|||
|
||||
final class PostDaoTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
|
||||
{
|
||||
private $fileServiceMock;
|
||||
private $thumbnailServiceMock;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->fileServiceMock = $this->mock(\Szurubooru\Services\FileService::class);
|
||||
$this->thumbnailServiceMock = $this->mock(\Szurubooru\Services\ThumbnailService::class);
|
||||
}
|
||||
|
||||
public function testCreating()
|
||||
{
|
||||
$postDao = $this->getPostDao();
|
||||
|
@ -116,9 +126,81 @@ final class PostDaoTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
|
|||
$this->assertEquals(2, count($tagDao->findAll()));
|
||||
}
|
||||
|
||||
public function testNotLoadingContentForNewPosts()
|
||||
{
|
||||
$postDao = $this->getPostDao();
|
||||
$newlyCreatedPost = $this->getPost();
|
||||
$this->assertNull($newlyCreatedPost->getContent());
|
||||
}
|
||||
|
||||
public function testLoadingContentPostsForExistingPosts()
|
||||
{
|
||||
$postDao = $this->getPostDao();
|
||||
$post = $this->getPost();
|
||||
$postDao->save($post);
|
||||
|
||||
$post = $postDao->findById($post->getId());
|
||||
|
||||
$this->fileServiceMock
|
||||
->expects($this->once())
|
||||
->method('load')
|
||||
->with($post->getContentPath())
|
||||
->willReturn('whatever');
|
||||
|
||||
$this->assertEquals('whatever', $post->getContent());
|
||||
}
|
||||
|
||||
public function testSavingContent()
|
||||
{
|
||||
$postDao = $this->getPostDao();
|
||||
$post = $this->getPost();
|
||||
$post->setContent('whatever');
|
||||
|
||||
$this->thumbnailServiceMock
|
||||
->expects($this->exactly(2))
|
||||
->method('deleteUsedThumbnails')
|
||||
->withConsecutive(
|
||||
[$post->getContentPath()],
|
||||
[$post->getThumbnailSourceContentPath()]);
|
||||
|
||||
$this->fileServiceMock
|
||||
->expects($this->once())
|
||||
->method('save')
|
||||
->with($post->getContentPath(), 'whatever');
|
||||
|
||||
$postDao->save($post);
|
||||
}
|
||||
public function testSavingContentAndThumbnail()
|
||||
{
|
||||
$postDao = $this->getPostDao();
|
||||
$post = $this->getPost();
|
||||
$post->setContent('whatever');
|
||||
$post->setThumbnailSourceContent('an image of sharks');
|
||||
|
||||
$this->thumbnailServiceMock
|
||||
->expects($this->exactly(2))
|
||||
->method('deleteUsedThumbnails')
|
||||
->withConsecutive(
|
||||
[$post->getContentPath()],
|
||||
[$post->getThumbnailSourceContentPath()]);
|
||||
|
||||
$this->fileServiceMock
|
||||
->expects($this->exactly(2))
|
||||
->method('save')
|
||||
->withConsecutive(
|
||||
[$post->getContentPath(), 'whatever'],
|
||||
[$post->getThumbnailSourceContentPath(), 'an image of sharks']);
|
||||
|
||||
$postDao->save($post);
|
||||
}
|
||||
|
||||
|
||||
private function getPostDao()
|
||||
{
|
||||
return new \Szurubooru\Dao\PostDao($this->databaseConnection);
|
||||
return new \Szurubooru\Dao\PostDao(
|
||||
$this->databaseConnection,
|
||||
$this->fileServiceMock,
|
||||
$this->thumbnailServiceMock);
|
||||
}
|
||||
|
||||
private function getTagDao()
|
||||
|
|
|
@ -8,7 +8,13 @@ class UserSearchServiceTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
|
|||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->userDao = new \Szurubooru\Dao\UserDao($this->databaseConnection);
|
||||
|
||||
$fileServiceMock = $this->mock(\Szurubooru\Services\FileService::class);
|
||||
$thumbnailServiceMock = $this->mock(\Szurubooru\Services\ThumbnailService::class);
|
||||
$this->userDao = new \Szurubooru\Dao\UserDao(
|
||||
$this->databaseConnection,
|
||||
$fileServiceMock,
|
||||
$thumbnailServiceMock);
|
||||
}
|
||||
|
||||
public function testNothing()
|
||||
|
@ -21,40 +27,59 @@ class UserSearchServiceTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
|
|||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
|
||||
public function testSorting()
|
||||
public function testDefaultOrder()
|
||||
{
|
||||
$user1 = $this->getTestUser('reginald');
|
||||
$user2 = $this->getTestUser('beartato');
|
||||
list ($user1, $user2) = $this->prepareUsers();
|
||||
$this->doTestSorting(null, [$user2]);
|
||||
}
|
||||
|
||||
public function testOrderByNameAscending()
|
||||
{
|
||||
list ($user1, $user2) = $this->prepareUsers();
|
||||
$this->doTestSorting('name,asc', [$user1]);
|
||||
}
|
||||
|
||||
public function testOrderByNameDescending()
|
||||
{
|
||||
list ($user1, $user2) = $this->prepareUsers();
|
||||
$this->doTestSorting('name,desc', [$user2]);
|
||||
}
|
||||
|
||||
public function testOrderByRegistrationTimeAscending()
|
||||
{
|
||||
list ($user1, $user2) = $this->prepareUsers();
|
||||
$this->doTestSorting('registrationTime,asc', [$user2]);
|
||||
}
|
||||
|
||||
public function testOrderByRegistrationTimeDescending()
|
||||
{
|
||||
list ($user1, $user2) = $this->prepareUsers();
|
||||
$this->doTestSorting('registrationTime,desc', [$user1]);
|
||||
}
|
||||
|
||||
private function prepareUsers()
|
||||
{
|
||||
$user1 = $this->getTestUser('beartato');
|
||||
$user2 = $this->getTestUser('reginald');
|
||||
$user1->setRegistrationTime(date('c', mktime(3, 2, 1)));
|
||||
$user2->setRegistrationTime(date('c', mktime(1, 2, 3)));
|
||||
|
||||
$this->userDao->save($user1);
|
||||
$this->userDao->save($user2);
|
||||
return [$user1, $user2];
|
||||
}
|
||||
|
||||
private function doTestSorting($order, $expectedUsers)
|
||||
{
|
||||
$userSearchService = $this->getUserSearchService();
|
||||
$searchFilter = new \Szurubooru\Dao\SearchFilter(1);
|
||||
$expected = new \Szurubooru\Dao\SearchResult($searchFilter, [$user2], 2);
|
||||
$actual = $userSearchService->getFiltered($searchFilter);
|
||||
$this->assertEquals($expected, $actual);
|
||||
if ($order !== null)
|
||||
$searchFilter->order = $order;
|
||||
|
||||
$searchFilter->order = 'name,asc';
|
||||
$expected = new \Szurubooru\Dao\SearchResult($searchFilter, [$user2], 2);
|
||||
$actual = $userSearchService->getFiltered($searchFilter);
|
||||
$this->assertEquals($expected, $actual);
|
||||
|
||||
$searchFilter->order = 'name,desc';
|
||||
$expected = new \Szurubooru\Dao\SearchResult($searchFilter, [$user1], 2);
|
||||
$actual = $userSearchService->getFiltered($searchFilter);
|
||||
$this->assertEquals($expected, $actual);
|
||||
|
||||
$searchFilter->order = 'registrationTime,desc';
|
||||
$expected = new \Szurubooru\Dao\SearchResult($searchFilter, [$user1], 2);
|
||||
$actual = $userSearchService->getFiltered($searchFilter);
|
||||
$this->assertEquals($expected, $actual);
|
||||
|
||||
$searchFilter->order = 'registrationTime';
|
||||
$expected = new \Szurubooru\Dao\SearchResult($searchFilter, [$user2], 2);
|
||||
$expected = new \Szurubooru\Dao\SearchResult($searchFilter, $expectedUsers, 2);
|
||||
$actual = $userSearchService->getFiltered($searchFilter);
|
||||
foreach ($actual->entities as $entity)
|
||||
$entity->resetLazyLoaders();
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,17 @@ namespace Szurubooru\Tests\Dao;
|
|||
|
||||
final class UserDaoTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
|
||||
{
|
||||
private $fileServiceMock;
|
||||
private $thumbnailServiceMock;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->fileServiceMock = $this->mock(\Szurubooru\Services\FileService::class);
|
||||
$this->thumbnailServiceMock = $this->mock(\Szurubooru\Services\ThumbnailService::class);
|
||||
}
|
||||
|
||||
public function testRetrievingByValidName()
|
||||
{
|
||||
$userDao = $this->getUserDao();
|
||||
|
@ -12,6 +23,7 @@ final class UserDaoTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
|
|||
|
||||
$expected = $user;
|
||||
$actual = $userDao->findByName($user->getName());
|
||||
$actual->resetLazyLoaders();
|
||||
$this->assertEquals($actual, $expected);
|
||||
}
|
||||
|
||||
|
@ -34,9 +46,68 @@ final class UserDaoTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
|
|||
$this->assertTrue($userDao->hasAnyUsers());
|
||||
}
|
||||
|
||||
public function testNotLoadingAvatarContentForNewUsers()
|
||||
{
|
||||
$userDao = $this->getUserDao();
|
||||
$user = $this->getTestUser();
|
||||
$user->setAvatarStyle(\Szurubooru\Entities\User::AVATAR_STYLE_MANUAL);
|
||||
$userDao->save($user);
|
||||
|
||||
$this->assertNull($user->getCustomAvatarSourceContent());
|
||||
}
|
||||
|
||||
public function testLoadingContentUsersForExistingUsers()
|
||||
{
|
||||
$userDao = $this->getUserDao();
|
||||
$user = $this->getTestUser();
|
||||
$user->setAvatarStyle(\Szurubooru\Entities\User::AVATAR_STYLE_MANUAL);
|
||||
$userDao->save($user);
|
||||
|
||||
$user = $userDao->findById($user->getId());
|
||||
|
||||
$this->fileServiceMock
|
||||
->expects($this->once())
|
||||
->method('load')
|
||||
->with($user->getCustomAvatarSourceContentPath())->willReturn('whatever');
|
||||
|
||||
$this->assertEquals('whatever', $user->getCustomAvatarSourceContent());
|
||||
}
|
||||
|
||||
public function testSavingContent()
|
||||
{
|
||||
$userDao = $this->getUserDao();
|
||||
$user = $this->getTestUser();
|
||||
$user->setAvatarStyle(\Szurubooru\Entities\User::AVATAR_STYLE_MANUAL);
|
||||
$user->setCustomAvatarSourceContent('whatever');
|
||||
|
||||
$this->thumbnailServiceMock
|
||||
->expects($this->once())
|
||||
->method('deleteUsedThumbnails')
|
||||
->with($this->callback(
|
||||
function($subject) use ($user)
|
||||
{
|
||||
return $subject == $user->getCustomAvatarSourceContentPath();
|
||||
}));
|
||||
|
||||
$this->fileServiceMock
|
||||
->expects($this->once())
|
||||
->method('save')
|
||||
->with($this->callback(
|
||||
function($subject) use ($user)
|
||||
{
|
||||
//callback is used because ->save() will create id, which is going to be used by the function below
|
||||
return $subject == $user->getCustomAvatarSourceContentPath();
|
||||
}), 'whatever');
|
||||
|
||||
$userDao->save($user);
|
||||
}
|
||||
|
||||
private function getUserDao()
|
||||
{
|
||||
return new \Szurubooru\Dao\UserDao($this->databaseConnection);
|
||||
return new \Szurubooru\Dao\UserDao(
|
||||
$this->databaseConnection,
|
||||
$this->fileServiceMock,
|
||||
$this->thumbnailServiceMock);
|
||||
}
|
||||
|
||||
private function getTestUser()
|
||||
|
|
|
@ -10,4 +10,10 @@ class InputReaderTest extends \Szurubooru\Tests\AbstractTestCase
|
|||
$expected = 'awesome dog';
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
|
||||
public function testDecodingEmptyBase64()
|
||||
{
|
||||
$inputReader = new \Szurubooru\Helpers\InputReader();
|
||||
$this->assertNull($inputReader->decodeBase64($inputReader->iDontEvenExist));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,8 +60,6 @@ class PostServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
|||
$formData->contentFileName = 'blah';
|
||||
|
||||
$this->postDaoMock->expects($this->once())->method('save')->will($this->returnArgument(0));
|
||||
$this->fileServiceMock->expects($this->once())->method('save');
|
||||
$this->fileServiceMock->expects($this->once())->method('getFullPath')->willReturn($this->getTestFilePath('image.jpg'));
|
||||
|
||||
$this->postService = $this->getPostService();
|
||||
$savedPost = $this->postService->createPost($formData);
|
||||
|
@ -82,8 +80,6 @@ class PostServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
|||
$formData->contentFileName = 'blah';
|
||||
|
||||
$this->postDaoMock->expects($this->once())->method('save')->will($this->returnArgument(0));
|
||||
$this->fileServiceMock->expects($this->once())->method('save');
|
||||
$this->fileServiceMock->expects($this->once())->method('getFullPath')->willReturn($this->getTestFilePath('video.mp4'));
|
||||
|
||||
$this->postService = $this->getPostService();
|
||||
$savedPost = $this->postService->createPost($formData);
|
||||
|
@ -104,8 +100,6 @@ class PostServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
|||
$formData->contentFileName = 'blah';
|
||||
|
||||
$this->postDaoMock->expects($this->once())->method('save')->will($this->returnArgument(0));
|
||||
$this->fileServiceMock->expects($this->once())->method('save');
|
||||
$this->fileServiceMock->expects($this->once())->method('getFullPath')->willReturn($this->getTestFilePath('flash.swf'));
|
||||
|
||||
$this->postService = $this->getPostService();
|
||||
$savedPost = $this->postService->createPost($formData);
|
||||
|
|
Loading…
Reference in a new issue