Added post relations
This commit is contained in:
parent
22b30c3e43
commit
5dc85b7dee
20 changed files with 213 additions and 18 deletions
2
TODO
2
TODO
|
@ -6,11 +6,9 @@ everything related to posts:
|
||||||
- fav
|
- fav
|
||||||
- score (see notes about scoring)
|
- score (see notes about scoring)
|
||||||
- editing
|
- editing
|
||||||
- relations
|
|
||||||
- ability to loop video posts
|
- ability to loop video posts
|
||||||
- post edit history (think
|
- post edit history (think
|
||||||
http://konachan.com/history?search=post%3A188614)
|
http://konachan.com/history?search=post%3A188614)
|
||||||
- relations
|
|
||||||
- previous and next post (difficult)
|
- previous and next post (difficult)
|
||||||
- extract Pager from PagedCollectionPresenter
|
- extract Pager from PagedCollectionPresenter
|
||||||
- rename PagedCollectionPresenter to PagerPresenter
|
- rename PagedCollectionPresenter to PagerPresenter
|
||||||
|
|
|
@ -48,7 +48,8 @@ changePostSafety = powerUser, moderator, administrator
|
||||||
changePostSource = regularUser, powerUser, moderator, administrator
|
changePostSource = regularUser, powerUser, moderator, administrator
|
||||||
changePostTags = regularUser, powerUser, moderator, administrator
|
changePostTags = regularUser, powerUser, moderator, administrator
|
||||||
changePostContent = regularUser, powerUser, moderator, administrator
|
changePostContent = regularUser, powerUser, moderator, administrator
|
||||||
changePostThumbnail = regularUser, powerUser, moderator, administrator
|
changePostThumbnail = powerUser, moderator, administrator
|
||||||
|
changePostRelations = regularUser, powerUser, moderator, administrator
|
||||||
|
|
||||||
listTags = anonymous, regularUser, powerUser, moderator, administrator
|
listTags = anonymous, regularUser, powerUser, moderator, administrator
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ App.Auth = function(_, jQuery, util, api, appState, promise) {
|
||||||
changePostTags: 'changePostTags',
|
changePostTags: 'changePostTags',
|
||||||
changePostContent: 'changePostContent',
|
changePostContent: 'changePostContent',
|
||||||
changePostThumbnail: 'changePostThumbnail',
|
changePostThumbnail: 'changePostThumbnail',
|
||||||
|
changePostRelations: 'changePostRelations',
|
||||||
|
|
||||||
listTags: 'listTags',
|
listTags: 'listTags',
|
||||||
};
|
};
|
||||||
|
|
|
@ -39,6 +39,7 @@ App.Presenters.PostPresenter = function(
|
||||||
editPrivileges.canChangeTags = auth.hasPrivilege(auth.privileges.changePostTags);
|
editPrivileges.canChangeTags = auth.hasPrivilege(auth.privileges.changePostTags);
|
||||||
editPrivileges.canChangeContent = auth.hasPrivilege(auth.privileges.changePostContent);
|
editPrivileges.canChangeContent = auth.hasPrivilege(auth.privileges.changePostContent);
|
||||||
editPrivileges.canChangeThumbnail = auth.hasPrivilege(auth.privileges.changePostThumbnail);
|
editPrivileges.canChangeThumbnail = auth.hasPrivilege(auth.privileges.changePostThumbnail);
|
||||||
|
editPrivileges.canChangeRelations = auth.hasPrivilege(auth.privileges.changePostRelations);
|
||||||
|
|
||||||
promise.waitAll(
|
promise.waitAll(
|
||||||
util.promiseTemplate('post'),
|
util.promiseTemplate('post'),
|
||||||
|
@ -190,6 +191,10 @@ App.Presenters.PostPresenter = function(
|
||||||
formData.tags = tagInput.getTags().join(' ');
|
formData.tags = tagInput.getTags().join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (editPrivileges.canChangeRelations) {
|
||||||
|
formData.relations = $form.find('[name=relations]').val();
|
||||||
|
}
|
||||||
|
|
||||||
if (post.tags.length === 0) {
|
if (post.tags.length === 0) {
|
||||||
showEditError('No tags set.');
|
showEditError('No tags set.');
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -39,6 +39,15 @@
|
||||||
</div>
|
</div>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
|
<% if (privileges.canChangeRelations) { %>
|
||||||
|
<div class="form-row">
|
||||||
|
<label class="form-label" for="post-relations">Relations:</label>
|
||||||
|
<div class="form-input">
|
||||||
|
<input maxlength="200" type="text" name="relations" id="post-relations" placeholder="Post ids, separated with space" value="<%= _.pluck(post.relations, 'id').join(' ') %>"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
<% if (privileges.canChangeContent) { %>
|
<% if (privileges.canChangeContent) { %>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<label class="form-label" for="post-content">Content:</label>
|
<label class="form-label" for="post-content">Content:</label>
|
||||||
|
|
|
@ -94,6 +94,19 @@
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<% if (_.any(post.relations)) { %>
|
||||||
|
<h1>Related posts</h1>
|
||||||
|
<ul class="related">
|
||||||
|
<% _.each(post.relations, function(relatedPost) { %>
|
||||||
|
<li>
|
||||||
|
<a href="#/post/<%= relatedPost.id %>">
|
||||||
|
<%= relatedPost.idMarkdown %>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<% }) %>
|
||||||
|
</ul>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
<% if (_.any(privileges) || _.any(editPrivileges)) { %>
|
<% if (_.any(privileges) || _.any(editPrivileges)) { %>
|
||||||
<h1>Options</h1>
|
<h1>Options</h1>
|
||||||
|
|
||||||
|
|
|
@ -35,20 +35,20 @@ final class PostController extends AbstractController
|
||||||
public function getFeatured()
|
public function getFeatured()
|
||||||
{
|
{
|
||||||
$post = $this->postService->getFeatured();
|
$post = $this->postService->getFeatured();
|
||||||
return $this->postViewProxy->fromEntity($post);
|
return $this->postViewProxy->fromEntity($post, $this->getFullFetchConfig());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getByNameOrId($postNameOrId)
|
public function getByNameOrId($postNameOrId)
|
||||||
{
|
{
|
||||||
$post = $this->postService->getByNameOrId($postNameOrId);
|
$post = $this->postService->getByNameOrId($postNameOrId);
|
||||||
return $this->postViewProxy->fromEntity($post);
|
return $this->postViewProxy->fromEntity($post, $this->getFullFetchConfig());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFiltered()
|
public function getFiltered()
|
||||||
{
|
{
|
||||||
$formData = new \Szurubooru\FormData\SearchFormData($this->inputReader);
|
$formData = new \Szurubooru\FormData\SearchFormData($this->inputReader);
|
||||||
$searchResult = $this->postService->getFiltered($formData);
|
$searchResult = $this->postService->getFiltered($formData);
|
||||||
$entities = $this->postViewProxy->fromArray($searchResult->getEntities());
|
$entities = $this->postViewProxy->fromArray($searchResult->getEntities(), $this->getLightFetchConfig());
|
||||||
return [
|
return [
|
||||||
'data' => $entities,
|
'data' => $entities,
|
||||||
'pageSize' => $searchResult->getPageSize(),
|
'pageSize' => $searchResult->getPageSize(),
|
||||||
|
@ -66,7 +66,7 @@ final class PostController extends AbstractController
|
||||||
$this->privilegeService->assertPrivilege(\Szurubooru\Privilege::UPLOAD_POSTS_ANONYMOUSLY);
|
$this->privilegeService->assertPrivilege(\Szurubooru\Privilege::UPLOAD_POSTS_ANONYMOUSLY);
|
||||||
|
|
||||||
$post = $this->postService->createPost($formData);
|
$post = $this->postService->createPost($formData);
|
||||||
return $this->postViewProxy->fromEntity($post);
|
return $this->postViewProxy->fromEntity($post, $this->getFullFetchConfig());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updatePost($postNameOrId)
|
public function updatePost($postNameOrId)
|
||||||
|
@ -91,7 +91,7 @@ final class PostController extends AbstractController
|
||||||
|
|
||||||
$this->postService->updatePost($post, $formData);
|
$this->postService->updatePost($post, $formData);
|
||||||
$post = $this->postService->getByNameOrId($postNameOrId);
|
$post = $this->postService->getByNameOrId($postNameOrId);
|
||||||
return $this->postViewProxy->fromEntity($post);
|
return $this->postViewProxy->fromEntity($post, $this->getFullFetchConfig());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deletePost($postNameOrId)
|
public function deletePost($postNameOrId)
|
||||||
|
@ -105,4 +105,22 @@ final class PostController extends AbstractController
|
||||||
$post = $this->postService->getByNameOrId($postNameOrId);
|
$post = $this->postService->getByNameOrId($postNameOrId);
|
||||||
$this->postService->featurePost($post);
|
$this->postService->featurePost($post);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getFullFetchConfig()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
[
|
||||||
|
\Szurubooru\Controllers\ViewProxies\PostViewProxy::FETCH_RELATIONS => true,
|
||||||
|
\Szurubooru\Controllers\ViewProxies\PostViewProxy::FETCH_TAGS => true,
|
||||||
|
\Szurubooru\Controllers\ViewProxies\PostViewProxy::FETCH_USER => true,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getLightFetchConfig()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
[
|
||||||
|
\Szurubooru\Controllers\ViewProxies\PostViewProxy::FETCH_TAGS => true,
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,14 @@ namespace Szurubooru\Controllers\ViewProxies;
|
||||||
|
|
||||||
abstract class AbstractViewProxy
|
abstract class AbstractViewProxy
|
||||||
{
|
{
|
||||||
public abstract function fromEntity($entity);
|
public abstract function fromEntity($entity, $config = []);
|
||||||
|
|
||||||
public function fromArray($entities)
|
public function fromArray($entities, $config = [])
|
||||||
{
|
{
|
||||||
return array_values(array_map(
|
return array_values(array_map(
|
||||||
function($entity)
|
function($entity) use ($config)
|
||||||
{
|
{
|
||||||
return static::fromEntity($entity);
|
return static::fromEntity($entity, $config);
|
||||||
},
|
},
|
||||||
$entities));
|
$entities));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,10 @@ namespace Szurubooru\Controllers\ViewProxies;
|
||||||
|
|
||||||
class PostViewProxy extends AbstractViewProxy
|
class PostViewProxy extends AbstractViewProxy
|
||||||
{
|
{
|
||||||
|
const FETCH_USER = 'fetchUser';
|
||||||
|
const FETCH_TAGS = 'fetchTags';
|
||||||
|
const FETCH_RELATIONS = 'fetchRelations';
|
||||||
|
|
||||||
private $tagViewProxy;
|
private $tagViewProxy;
|
||||||
private $userViewProxy;
|
private $userViewProxy;
|
||||||
|
|
||||||
|
@ -14,7 +18,7 @@ class PostViewProxy extends AbstractViewProxy
|
||||||
$this->userViewProxy = $userViewProxy;
|
$this->userViewProxy = $userViewProxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function fromEntity($post)
|
public function fromEntity($post, $config = [])
|
||||||
{
|
{
|
||||||
$result = new \StdClass;
|
$result = new \StdClass;
|
||||||
if ($post)
|
if ($post)
|
||||||
|
@ -34,9 +38,16 @@ class PostViewProxy extends AbstractViewProxy
|
||||||
$result->imageHeight = $post->getImageHeight();
|
$result->imageHeight = $post->getImageHeight();
|
||||||
$result->featureCount = $post->getFeatureCount();
|
$result->featureCount = $post->getFeatureCount();
|
||||||
$result->lastFeatureTime = $post->getLastFeatureTime();
|
$result->lastFeatureTime = $post->getLastFeatureTime();
|
||||||
$result->tags = $this->tagViewProxy->fromArray($post->getTags());
|
|
||||||
$result->originalFileSize = $post->getOriginalFileSize();
|
$result->originalFileSize = $post->getOriginalFileSize();
|
||||||
|
|
||||||
|
if (!empty($config[self::FETCH_TAGS]))
|
||||||
|
$result->tags = $this->tagViewProxy->fromArray($post->getTags());
|
||||||
|
|
||||||
|
if (!empty($config[self::FETCH_USER]))
|
||||||
$result->user = $this->userViewProxy->fromEntity($post->getUser());
|
$result->user = $this->userViewProxy->fromEntity($post->getUser());
|
||||||
|
|
||||||
|
if (!empty($config[self::FETCH_RELATIONS]))
|
||||||
|
$result->relations = $this->fromArray($post->getRelatedPosts());
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ namespace Szurubooru\Controllers\ViewProxies;
|
||||||
|
|
||||||
class TagViewProxy extends AbstractViewProxy
|
class TagViewProxy extends AbstractViewProxy
|
||||||
{
|
{
|
||||||
public function fromEntity($tag)
|
public function fromEntity($tag, $config = [])
|
||||||
{
|
{
|
||||||
$result = new \StdClass;
|
$result = new \StdClass;
|
||||||
if ($tag)
|
if ($tag)
|
||||||
|
|
|
@ -3,7 +3,7 @@ namespace Szurubooru\Controllers\ViewProxies;
|
||||||
|
|
||||||
class TokenViewProxy extends AbstractViewProxy
|
class TokenViewProxy extends AbstractViewProxy
|
||||||
{
|
{
|
||||||
public function fromEntity($token)
|
public function fromEntity($token, $config = [])
|
||||||
{
|
{
|
||||||
$result = new \StdClass;
|
$result = new \StdClass;
|
||||||
if ($token)
|
if ($token)
|
||||||
|
|
|
@ -10,7 +10,7 @@ class UserViewProxy extends AbstractViewProxy
|
||||||
$this->privilegeService = $privilegeService;
|
$this->privilegeService = $privilegeService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function fromEntity($user)
|
public function fromEntity($user, $config = [])
|
||||||
{
|
{
|
||||||
$result = new \StdClass;
|
$result = new \StdClass;
|
||||||
if ($user)
|
if ($user)
|
||||||
|
|
|
@ -76,6 +76,13 @@ class PostDao extends AbstractDao implements ICrudDao
|
||||||
{
|
{
|
||||||
return $this->getTags($post);
|
return $this->getTags($post);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$post->setLazyLoader(
|
||||||
|
\Szurubooru\Entities\Post::LAZY_LOADER_RELATED_POSTS,
|
||||||
|
function(\Szurubooru\Entities\Post $post)
|
||||||
|
{
|
||||||
|
return $this->getRelatedPosts($post);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function afterSave(\Szurubooru\Entities\Entity $post)
|
protected function afterSave(\Szurubooru\Entities\Entity $post)
|
||||||
|
@ -83,6 +90,7 @@ class PostDao extends AbstractDao implements ICrudDao
|
||||||
$this->syncContent($post);
|
$this->syncContent($post);
|
||||||
$this->syncThumbnailSourceContent($post);
|
$this->syncThumbnailSourceContent($post);
|
||||||
$this->syncTags($post);
|
$this->syncTags($post);
|
||||||
|
$this->syncPostRelations($post);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getTags(\Szurubooru\Entities\Post $post)
|
private function getTags(\Szurubooru\Entities\Post $post)
|
||||||
|
@ -95,6 +103,28 @@ class PostDao extends AbstractDao implements ICrudDao
|
||||||
return $this->userDao->findById($post->getUserId());
|
return $this->userDao->findById($post->getUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getRelatedPosts(\Szurubooru\Entities\Post $post)
|
||||||
|
{
|
||||||
|
$query = $this->fpdo
|
||||||
|
->from('postRelations')
|
||||||
|
->where('post1id = :post1id OR post2id = :post2id', [
|
||||||
|
':post1id' => $post->getId(),
|
||||||
|
':post2id' => $post->getId()]);
|
||||||
|
|
||||||
|
$relatedPostIds = [];
|
||||||
|
foreach ($query as $arrayEntity)
|
||||||
|
{
|
||||||
|
$post1id = intval($arrayEntity['post1id']);
|
||||||
|
$post2id = intval($arrayEntity['post2id']);
|
||||||
|
if ($post1id !== $post->getId())
|
||||||
|
$relatedPostIds[] = $post1id;
|
||||||
|
if ($post2id !== $post->getId())
|
||||||
|
$relatedPostIds[] = $post2id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->findByIds($relatedPostIds);
|
||||||
|
}
|
||||||
|
|
||||||
private function syncContent(\Szurubooru\Entities\Post $post)
|
private function syncContent(\Szurubooru\Entities\Post $post)
|
||||||
{
|
{
|
||||||
$targetPath = $post->getContentPath();
|
$targetPath = $post->getContentPath();
|
||||||
|
@ -154,4 +184,29 @@ class PostDao extends AbstractDao implements ICrudDao
|
||||||
$this->fpdo->deleteFrom('postTags')->where('postId', $post->getId())->where('tagId', $tagId)->execute();
|
$this->fpdo->deleteFrom('postTags')->where('postId', $post->getId())->where('tagId', $tagId)->execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function syncPostRelations(\Szurubooru\Entities\Post $post)
|
||||||
|
{
|
||||||
|
$this->fpdo->deleteFrom('postRelations')->where('post1id', $post->getId())->execute();
|
||||||
|
$this->fpdo->deleteFrom('postRelations')->where('post2id', $post->getId())->execute();
|
||||||
|
|
||||||
|
$relatedPostIds = array_filter(array_unique(array_map(
|
||||||
|
function ($post)
|
||||||
|
{
|
||||||
|
if (!$post->getId())
|
||||||
|
throw new \RuntimeException('Unsaved entities found');
|
||||||
|
return $post->getId();
|
||||||
|
},
|
||||||
|
$post->getRelatedPosts())));
|
||||||
|
|
||||||
|
foreach ($relatedPostIds as $postId)
|
||||||
|
{
|
||||||
|
$this->fpdo
|
||||||
|
->insertInto('postRelations')
|
||||||
|
->values([
|
||||||
|
'post1id' => $post->getId(),
|
||||||
|
'post2id' => $postId])
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ final class Post extends Entity
|
||||||
const LAZY_LOADER_TAGS = 'tags';
|
const LAZY_LOADER_TAGS = 'tags';
|
||||||
const LAZY_LOADER_CONTENT = 'content';
|
const LAZY_LOADER_CONTENT = 'content';
|
||||||
const LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT = 'thumbnailSourceContent';
|
const LAZY_LOADER_THUMBNAIL_SOURCE_CONTENT = 'thumbnailSourceContent';
|
||||||
|
const LAZY_LOADER_RELATED_POSTS = 'relatedPosts';
|
||||||
|
|
||||||
const META_TAG_COUNT = 'tagCount';
|
const META_TAG_COUNT = 'tagCount';
|
||||||
|
|
||||||
|
@ -201,6 +202,16 @@ final class Post extends Entity
|
||||||
$this->setMeta(self::META_TAG_COUNT, count($tags));
|
$this->setMeta(self::META_TAG_COUNT, count($tags));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getRelatedPosts()
|
||||||
|
{
|
||||||
|
return $this->lazyLoad(self::LAZY_LOADER_RELATED_POSTS, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setRelatedPosts(array $relatedPosts)
|
||||||
|
{
|
||||||
|
$this->lazySave(self::LAZY_LOADER_RELATED_POSTS, $relatedPosts);
|
||||||
|
}
|
||||||
|
|
||||||
public function getUser()
|
public function getUser()
|
||||||
{
|
{
|
||||||
return $this->lazyLoad(self::LAZY_LOADER_USER, null);
|
return $this->lazyLoad(self::LAZY_LOADER_USER, null);
|
||||||
|
|
|
@ -8,6 +8,7 @@ class PostEditFormData implements \Szurubooru\IValidatable
|
||||||
public $safety;
|
public $safety;
|
||||||
public $source;
|
public $source;
|
||||||
public $tags;
|
public $tags;
|
||||||
|
public $relations;
|
||||||
|
|
||||||
public $seenEditTime;
|
public $seenEditTime;
|
||||||
|
|
||||||
|
@ -20,6 +21,7 @@ class PostEditFormData implements \Szurubooru\IValidatable
|
||||||
$this->safety = \Szurubooru\Helpers\EnumHelper::postSafetyFromString($inputReader->safety);
|
$this->safety = \Szurubooru\Helpers\EnumHelper::postSafetyFromString($inputReader->safety);
|
||||||
$this->source = $inputReader->source;
|
$this->source = $inputReader->source;
|
||||||
$this->tags = preg_split('/[\s+]/', $inputReader->tags);
|
$this->tags = preg_split('/[\s+]/', $inputReader->tags);
|
||||||
|
$this->relations = array_filter(preg_split('/[\s+]/', $inputReader->relations));
|
||||||
$this->seenEditTime = $inputReader->seenEditTime;
|
$this->seenEditTime = $inputReader->seenEditTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,5 +32,11 @@ class PostEditFormData implements \Szurubooru\IValidatable
|
||||||
|
|
||||||
if ($this->source !== null)
|
if ($this->source !== null)
|
||||||
$validator->validatePostSource($this->source);
|
$validator->validatePostSource($this->source);
|
||||||
|
|
||||||
|
if ($this->relations)
|
||||||
|
{
|
||||||
|
foreach ($this->relations as $relatedPostId)
|
||||||
|
$validator->validateNumber($relatedPostId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ class Privilege
|
||||||
const CHANGE_POST_TAGS = 'changePostTags';
|
const CHANGE_POST_TAGS = 'changePostTags';
|
||||||
const CHANGE_POST_CONTENT = 'changePostContent';
|
const CHANGE_POST_CONTENT = 'changePostContent';
|
||||||
const CHANGE_POST_THUMBNAIL = 'changePostThumbnail';
|
const CHANGE_POST_THUMBNAIL = 'changePostThumbnail';
|
||||||
|
const CHANGE_POST_RELATIONS = 'changePostRelations';
|
||||||
|
|
||||||
const LIST_TAGS = 'listTags';
|
const LIST_TAGS = 'listTags';
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,6 +136,9 @@ class PostService
|
||||||
if ($formData->tags !== null)
|
if ($formData->tags !== null)
|
||||||
$this->updatePostTags($post, $formData->tags);
|
$this->updatePostTags($post, $formData->tags);
|
||||||
|
|
||||||
|
if ($formData->relations !== null)
|
||||||
|
$this->updatePostRelations($post, $formData->relations);
|
||||||
|
|
||||||
return $this->postDao->save($post);
|
return $this->postDao->save($post);
|
||||||
};
|
};
|
||||||
return $this->transactionManager->commit($transactionFunc);
|
return $this->transactionManager->commit($transactionFunc);
|
||||||
|
@ -244,6 +247,16 @@ class PostService
|
||||||
$post->setTags($tags);
|
$post->setTags($tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function updatePostRelations(\Szurubooru\Entities\Post $post, array $newRelatedPostIds)
|
||||||
|
{
|
||||||
|
$relatedPosts = $this->postDao->findByIds($newRelatedPostIds);
|
||||||
|
foreach ($newRelatedPostIds as $postId)
|
||||||
|
if (!isset($relatedPosts[$postId]))
|
||||||
|
throw new \DomainException('Post with id "' . $postId . '" was not found.');
|
||||||
|
|
||||||
|
$post->setRelatedPosts($relatedPosts);
|
||||||
|
}
|
||||||
|
|
||||||
public function deletePost(\Szurubooru\Entities\Post $post)
|
public function deletePost(\Szurubooru\Entities\Post $post)
|
||||||
{
|
{
|
||||||
$transactionFunc = function() use ($post)
|
$transactionFunc = function() use ($post)
|
||||||
|
|
19
src/Upgrades/Upgrade08.php
Normal file
19
src/Upgrades/Upgrade08.php
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\Upgrades;
|
||||||
|
|
||||||
|
class Upgrade08 implements IUpgrade
|
||||||
|
{
|
||||||
|
public function run(\Szurubooru\DatabaseConnection $databaseConnection)
|
||||||
|
{
|
||||||
|
$pdo = $databaseConnection->getPDO();
|
||||||
|
|
||||||
|
$pdo->exec('CREATE TABLE postRelations
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
post1id INTEGER NOT NULL,
|
||||||
|
post2id INTEGER NOT NULL,
|
||||||
|
UNIQUE (post1id, post2id)
|
||||||
|
)');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ return [
|
||||||
$container->get(\Szurubooru\Upgrades\Upgrade05::class),
|
$container->get(\Szurubooru\Upgrades\Upgrade05::class),
|
||||||
$container->get(\Szurubooru\Upgrades\Upgrade06::class),
|
$container->get(\Szurubooru\Upgrades\Upgrade06::class),
|
||||||
$container->get(\Szurubooru\Upgrades\Upgrade07::class),
|
$container->get(\Szurubooru\Upgrades\Upgrade07::class),
|
||||||
|
$container->get(\Szurubooru\Upgrades\Upgrade08::class),
|
||||||
];
|
];
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|
|
@ -159,6 +159,37 @@ final class PostDaoTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
|
||||||
$this->assertEquals(2, count($tagDao->findAll()));
|
$this->assertEquals(2, count($tagDao->findAll()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSavingUnsavedRelations()
|
||||||
|
{
|
||||||
|
$post1 = $this->getPost();
|
||||||
|
$post2 = $this->getPost();
|
||||||
|
$testPosts = [$post1, $post2];
|
||||||
|
|
||||||
|
$postDao = $this->getPostDao();
|
||||||
|
$post = $this->getPost();
|
||||||
|
$post->setRelatedPosts($testPosts);
|
||||||
|
$this->setExpectedException(\Exception::class, 'Unsaved entities found');
|
||||||
|
$postDao->save($post);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSavingRelations()
|
||||||
|
{
|
||||||
|
$post1 = $this->getPost();
|
||||||
|
$post2 = $this->getPost();
|
||||||
|
$testPosts = [$post1, $post2];
|
||||||
|
|
||||||
|
$postDao = $this->getPostDao();
|
||||||
|
$postDao->save($post1);
|
||||||
|
$postDao->save($post2);
|
||||||
|
$post = $this->getPost();
|
||||||
|
$post->setRelatedPosts($testPosts);
|
||||||
|
$postDao->save($post);
|
||||||
|
|
||||||
|
$savedPost = $postDao->findById($post->getId());
|
||||||
|
$this->assertEntitiesEqual($testPosts, $post->getRelatedPosts());
|
||||||
|
$this->assertEquals(2, count($savedPost->getRelatedPosts()));
|
||||||
|
}
|
||||||
|
|
||||||
public function testSavingUser()
|
public function testSavingUser()
|
||||||
{
|
{
|
||||||
$testUser = new \Szurubooru\Entities\User(5);
|
$testUser = new \Szurubooru\Entities\User(5);
|
||||||
|
|
Loading…
Reference in a new issue