Completed
Push — master ( be4f62...2d65d5 )
by Maxence
07:26
created

PictureRepository::findAllImages()   D

Complexity

Conditions 9
Paths 24

Size

Total Lines 37
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
dl 0
loc 37
ccs 0
cts 23
cp 0
rs 4.909
c 0
b 0
f 0
cc 9
eloc 28
nc 24
nop 2
crap 90
1
<?php
2
3
namespace ParseServerMigration\Console;
4
5
use GuzzleHttp\Psr7\CachingStream;
6
use GuzzleHttp\Psr7\Stream;
7
use MongoDB\Collection;
8
use Parse\ParseObject;
9
use Aws\S3\S3Client;
10
use Parse\ParseQuery;
11
use ParseServerMigration\Config;
12
use MongoDB\Client;
13
14
/**
15
 * Class PictureUploader.
16
 *
17
 * @author Maxence Dupressoir <[email protected]>
18
 * @copyright 2016 Meetic
19
 */
20
class PictureRepository
21
{
22
    /**
23
     * @var S3Client
24
     */
25
    private $s3Client;
26
27
    /**
28
     * @var Client
29
     */
30
    private $mongoDbClient;
31
32
    /**
33
     * @param S3Client $s3Client
34
     * @param Client   $mongoDbClient
35
     */
36 7
    public function __construct(S3Client $s3Client, Client $mongoDbClient)
37
    {
38 7
        $this->s3Client = $s3Client;
39 7
        $this->mongoDbClient = $mongoDbClient;
40 7
    }
41
42
    /**
43
     * @param $limit
44
     * @param bool $orderDesc
45
     * @throws \Exception
46
     *
47
     * @return \Parse\ParseObject[]|\Generator
48
     */
49
    public function findAllImages(int $limit, bool $orderDesc = false) : \Generator
50
    {
51
        $query = new ParseQuery(Config::PARSE_FILES_CLASS_NAME);
52
        if ($orderDesc) {
53
            $query->descending('createdAt');
54
        } else {
55
            $query->ascending('createdAt');
56
        }
57
        $found = false;
58
        do {
59
            /** @var ParseObject[] $result */
60
            if (isset($result)) {
61
                if ($orderDesc) {
62
                    $query->lessThan('createdAt', $result[count($result) - 1]->getCreatedAt());
63
                } else {
64
                    $query->greaterThan('createdAt', $result[count($result) - 1]->getCreatedAt());
65
                }
66
            }
67
            $result = $query
68
                ->limit($limit)
69
                ->exists(Config::PARSE_FILES_FIELD_NAME)
70
                ->notEqualTo(Config::PARSE_FILES_FIELD_NAME, null)
71
                ->find();
72
            if (count($result) > 0) {
73
                $found = true;
74
                $limit -= count($result);
75
                yield $result;
76
            }
77
        } while((count($result) > 0) && ($limit > 0));
78
        if ((count($result) === 0) && (!$found)) {
79
            throw new \Exception(
80
                'Can not find any record '.Config::PARSE_FILES_CLASS_NAME.':'.Config::PARSE_FILES_FIELD_NAME.'.'
81
                .' The error could be in class (absentee collection)'
82
                .' or in field (absentee document with such field)'
83
            );
84
        }
85
    }
86
87
    /**
88
     * @param ParseObject $picture
89
     *
90
     * @return \MongoDB\UpdateResult
91
     *
92
     * @throws \Exception
93
     */
94 1 View Code Duplication
    public function renameImage(ParseObject $picture)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
95
    {
96 1
        $originalFileName = $picture->get(Config::PARSE_FILES_FIELD_NAME)->getName();
97
98 1
        $updateResult = $this->renamePicture($originalFileName, Config::PARSE_FILES_FIELD_NAME);
99
100 1
        return $updateResult;
101
    }
102
103
    /**
104
     * @param ParseObject $picture
105
     *
106
     * @return \MongoDB\UpdateResult
107
     *
108
     * @throws \Exception
109
     */
110 1 View Code Duplication
    public function renameThumbnail(ParseObject $picture)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
111
    {
112 1
        $originalFileName = $picture->get(Config::PARSE_FILES_THUMBNAIL_FIELD_NAME)->getName();
113
114 1
        $updateResult = $this->renamePicture($originalFileName, Config::PARSE_FILES_THUMBNAIL_FIELD_NAME);
115
116 1
        return $updateResult;
117
    }
118
119
    /**
120
     * @param string $originalFileName
121
     * @param string $fieldName
122
     *
123
     * @return \MongoDB\UpdateResult
124
     */
125 2
    private function renamePicture(string $originalFileName, string $fieldName)
126
    {
127 2
        $formattedFileName = $this->getFileNameFromUrl($originalFileName);
128
129
        /** @var Collection $collection */
130 2
        $collection = $this->mongoDbClient->selectCollection(Config::MONGO_DB_NAME, Config::PARSE_FILES_CLASS_NAME);
131
132 2
        $updateResult = $collection->updateOne(
133 2
            [$fieldName => $originalFileName],
134 2
            ['$set' => [$fieldName => $formattedFileName]]
135
        );
136
137 2
        return $updateResult;
138
    }
139
140
    /**
141
     * @param ParseObject $picture
142
     *
143
     * @return array
144
     *
145
     * @throws \Exception
146
     */
147 1
    public function uploadImage(ParseObject $picture)
148
    {
149 1
        $imageUrl = $picture->get(Config::PARSE_FILES_FIELD_NAME)->getURL();
150
151 1
        return $this->uploadPicture($imageUrl);
152
    }
153
154
    /**
155
     * @param ParseObject $picture
156
     *
157
     * @return array
158
     *
159
     * @throws \Exception
160
     */
161
    public function uploadThumbnail(ParseObject $picture)
162
    {
163
        $imageUrl = $picture->get(Config::PARSE_FILES_THUMBNAIL_FIELD_NAME)->getURL();
164
165
        return $this->uploadPicture($imageUrl);
166
    }
167
168
    /**
169
     * @param string $imageUrl
170
     *
171
     * @return array
172
     *
173
     * @throws \Exception
174
     */
175 1
    private function uploadPicture(string $imageUrl)
176
    {
177 1
        $stream = new CachingStream($this->getFileStream($imageUrl));
178
179 1
        $result = $this->s3Client->putObject([
180 1
            'Bucket' => Config::S3_BUCKET,
181 1
            'Key' => Config::S3_UPLOAD_FOLDER.'/'.$this->getFileNameFromUrl($imageUrl),
182 1
            'Body' => $stream,
183
            'ContentType' => Config::PARSE_FILES_CONTENT_TYPE,
184 1
            'ACL' => 'public-read',
185
        ]);
186
187 1
        return $result->toArray();
188
    }
189
190
    /**
191
     * @param ParseObject $picture
192
     *
193
     * @return array
194
     */
195 2
    public function deletePicture(ParseObject $picture)
196
    {
197 2
        $result = $this->s3Client->deleteObject(array(
198 2
            'Bucket' => Config::S3_BUCKET,
199 2
            'Key' => Config::S3_UPLOAD_FOLDER.'/'.$this->getFileNameFromUrl($picture->get(Config::PARSE_FILES_FIELD_NAME)->getURL()),
200
        ));
201
202 1
        return $result->toArray();
203
    }
204
205
    /**
206
     * This will actually read from Parse server and insert data into a given MongoDB database.
207
     *
208
     * @return \MongoDB\InsertManyResult
209
     *
210
     * @throws \Exception
211
     */
212
    public function migrateAllPictures()
213
    {
214
        /** @var Collection $collection */
215
        $collection = $this->mongoDbClient->selectCollection(Config::MONGO_DB_NAME, Config::PARSE_FILES_CLASS_NAME);
216
217
        $query = new ParseQuery(Config::PARSE_FILES_CLASS_NAME);
218
219
        $objects = [];
220
221
        $query->each(function (ParseObject $picture) use ($objects) {
222
            $objects[] = $this->buildDocumentFromParseObject($picture);
223
        });
224
225
        return $collection->insertMany($objects);
226
    }
227
228
    //Below methods should probably be extracted to dedicated components
229
    /**
230
     * @param string $url
231
     *
232
     * @return string
233
     */
234 5
    private function getFileNameFromUrl(string $url)
235
    {
236 5
        $url = explode('/', $url);
237 5
        $fileName = end($url);
238 5
        $cleanFileName = str_replace('-', '', str_replace('tfss', '', $fileName));
239
240 5
        return $cleanFileName;
241
    }
242
243
    /**
244
     * @param string $url
245
     *
246
     * @return Stream
247
     *
248
     * @throws \ErrorException
249
     */
250 1
    private function getFileStream(string $url)
251
    {
252 1
        $url = str_replace('invalid-file-key', Config::PARSE_FILE_KEY, $url);
253
254 1
        $fstream = fopen($url, 'r');
255
256 1
        if ($fstream !== false) {
257 1
            return new Stream($fstream);
258
        }
259
260
        $error = error_get_last();
261
        throw new \ErrorException($error['message']);
262
    }
263
264
    /**
265
     * @param ParseObject $picture
266
     *
267
     * @return array
268
     */
269
    private function buildDocumentFromParseObject(ParseObject $picture)
270
    {
271
        return array(
272
            Config::PARSE_FILES_FIELD_NAME => $this->getFileNameFromUrl($picture->get(Config::PARSE_FILES_FIELD_NAME)->getName()),
273
        );
274
    }
275
}
276