Test Setup Failed
Push — master ( 8f8f69...6c321a )
by Alexey
02:36
created

PostFactory::findOrCreateFromDtoWithContent()   C

Complexity

Conditions 7
Paths 5

Size

Total Lines 33
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
dl 0
loc 33
ccs 0
cts 18
cp 0
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 21
nc 5
nop 1
crap 56
1
<?php
2
3
namespace Skobkin\Bundle\PointToolsBundle\Service\Factory\Blogs;
4
5
use Doctrine\ORM\EntityManagerInterface;
6
use Psr\Log\LoggerInterface;
7
use Skobkin\Bundle\PointToolsBundle\DTO\Api\{MetaPost, Post as PostDTO, PostsPage};
8
use Skobkin\Bundle\PointToolsBundle\Entity\{Blogs\Post, Blogs\PostTag, User};
9
use Skobkin\Bundle\PointToolsBundle\Exception\{Api\InvalidResponseException, Factory\Blog\InvalidDataException};
10
use Skobkin\Bundle\PointToolsBundle\Repository\Blogs\PostRepository;
11
use Skobkin\Bundle\PointToolsBundle\Service\Factory\{AbstractFactory, UserFactory};
12
13
class PostFactory extends AbstractFactory
14
{
15
    /** @var EntityManagerInterface */
16
    private $em;
17
18
    /** @var PostRepository */
19
    private $postRepository;
20
21
    /** @var UserFactory */
22
    private $userFactory;
23
24
    /** @var FileFactory */
25
    private $fileFactory;
26
27
    /** @var CommentFactory */
28
    private $commentFactory;
29
30
    /** @var TagFactory */
31
    private $tagFactory;
32
33
34
    public function __construct(
35
        LoggerInterface $logger,
36
        EntityManagerInterface $em,
37
        PostRepository $postRepository,
38
        UserFactory $userFactory,
39
        FileFactory $fileFactory,
40
        CommentFactory $commentFactory,
41
        TagFactory $tagFactory
42
    ) {
43
        parent::__construct($logger);
44
        $this->em = $em;
45
        $this->postRepository = $postRepository;
46
        $this->userFactory = $userFactory;
0 ignored issues
show
Documentation Bug introduced by
It seems like $userFactory of type object<Skobkin\Bundle\Po...ce\Factory\UserFactory> is incompatible with the declared type object<UserFactory> of property $userFactory.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
47
        $this->fileFactory = $fileFactory;
48
        $this->commentFactory = $commentFactory;
49
        $this->tagFactory = $tagFactory;
50
    }
51
52
    /**
53
     * Creates posts and return status of new insertions
54
     *
55
     * @throws InvalidResponseException
56
     */
57
    public function createFromPageDTO(PostsPage $page): bool
58
    {
59
        $posts = [];
60
61
        $hasNew = false;
62
63
        foreach ((array) $page->getPosts() as $postData) {
64
            try {
65
                if (null === $this->postRepository->find($postData->getPost()->getId())) {
66
                    $hasNew = true;
67
                }
68
69
                $post = $this->findOrCreateFromDtoWithContent($postData);
70
                $posts[] = $post;
71
            } catch (\Exception $e) {
72
                $this->logger->error('Error while processing post DTO', [
73
                    'post_id' => $postData->getPost()->getId(),
74
                    'exception' => get_class($e),
75
                    'message' => $e->getMessage(),
76
                    'file' => $e->getFile(),
77
                    'line' => $e->getLine(),
78
                ]);
79
            }
80
        }
81
82
        foreach ($posts as $post) {
83
            // @todo probably refactor?
84
            if ($this->em->getUnitOfWork()->isScheduledForInsert($post)) {
85
                $hasNew = true;
86
            }
87
        }
88
89
        return $hasNew;
90
    }
91
92
    /**
93
     * Create full post with tags, files and comments
94
     *
95
     * @todo Implement comments
96
     *
97
     * @throws InvalidDataException
98
     */
99
    public function findOrCreateFromDtoWithContent(MetaPost $metaPost): Post
100
    {
101
        if (!$metaPost->isValid()) {
102
            throw new InvalidDataException('Invalid post data');
103
        }
104
105
        $postData = $metaPost->getPost();
106
107
        try {
108
            $author = $this->userFactory->findOrCreateFromDTO($metaPost->getPost()->getAuthor());
109
        } catch (\Exception $e) {
110
            $this->logger->error('Error while creating user from DTO');
111
            throw $e;
112
        }
113
114
        $post = $this->findOrCreateFromDto($postData, $author);
115
116
        try {
117
            $this->updatePostTags($post, $postData->getTags() ?: []);
118
        } catch (\Exception $e) {
119
            $this->logger->error('Error while updating post tags');
120
            throw $e;
121
        }
122
123
        try {
124
            $this->updatePostFiles($post, $postData->getFiles() ?: []);
125
        } catch (\Exception $e) {
126
            $this->logger->error('Error while updating post files');
127
            throw $e;
128
        }
129
130
        return $post;
131
    }
132
133
    private function findOrCreateFromDto(PostDTO $postData, User $author): Post
134
    {
135
        if (null === ($post = $this->postRepository->find($postData->getId()))) {
136
            // Creating new post
137
            $post = new Post(
138
                $postData->getId(),
139
                $author,
140
                new \DateTime($postData->getCreated()),
141
                $postData->getType() ?: Post::TYPE_POST
142
            );
143
            $this->postRepository->add($post);
144
        }
145
146
        $post
147
            ->setText($postData->getText())
148
            ->setPrivate($postData->getPrivate())
149
        ;
150
151
        return $post;
152
    }
153
154
    /**
155
     * @param Post $post
156
     * @param string[] $tagsStrings
157
     */
158
    private function updatePostTags(Post $post, array $tagsStrings): void
159
    {
160
        $tags = $this->tagFactory->createFromStringsArray($tagsStrings);
161
162
        // Hashing tags strings
163
        $tagStringsHash = [];
164
        foreach ($tagsStrings as $tagsString) {
165
            $tagStringsHash[mb_strtolower($tagsString)] = $tagsString;
166
        }
167
168
        // Hashing current post tags
169
        $newTagsHash = [];
170
        foreach ($tags as $tag) {
171
            $newTagsHash[mb_strtolower($tag->getText())] = $tag;
172
        }
173
174
        // Hashing old post tags (from DB)
175
        $oldTagsHash = [];
176
        foreach ($post->getPostTags() as $postTag) {
177
            $oldTagsHash[mb_strtolower($postTag->getOriginalTagText())] = $postTag;
178
        }
179
180
        // Adding missing tags
181
        foreach ($tags as $tag) {
182
            if (!array_key_exists(mb_strtolower($tag->getText()), $oldTagsHash)) {
183
                $tmpPostTag = new PostTag($post, $tag, $tagStringsHash[mb_strtolower($tag->getText())]);
184
                $post->addPostTag($tmpPostTag);
185
            }
186
        }
187
188
        // Removing deleted tags
189
        foreach ($post->getPostTags() as $postTag) {
190
            if (!array_key_exists(mb_strtolower($postTag->getOriginalTagText()), $newTagsHash)) {
191
                $post->removePostTag($postTag);
192
            }
193
        }
194
    }
195
196
    /**
197
     * @param Post $post
198
     * @param array $urls
199
     */
200
    private function updatePostFiles(Post $post, array $urls): void
201
    {
202
        $files = $this->fileFactory->createFromUrlsArray($urls);
203
204
        // Adding missing files
205
        foreach ($files as $file) {
206
            if (!$post->getFiles()->contains($file)) {
207
                $post->addFile($file);
208
            }
209
        }
210
211
        // Removing deleted files
212
        foreach ($post->getFiles() as $file) {
213
            if (!in_array($file, $files, true)) {
214
                $post->removeFile($file);
215
            }
216
        }
217
    }
218
}