Passed
Push — master ( b91050...6fb96f )
by Jens
02:59
created

publishOrUnpublishDocumentByPath()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 23
Code Lines 13

Duplication

Lines 5
Ratio 21.74 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 3
eloc 13
c 2
b 1
f 0
nc 4
nop 2
dl 5
loc 23
rs 9.0856
1
<?php
2
3
namespace CloudControl\Cms\storage\repository {
4
5
    use CloudControl\Cms\storage\entities\Document;
6
    use CloudControl\Cms\storage\Repository;
7
    use CloudControl\Cms\storage\storage\DocumentStorage;
8
9
    /**
10
     * Created by jensk on 4-9-2017.
11
     */
12
    class ContentRepository
13
    {
14
        protected $storagePath;
15
        protected $contentDbHandle;
16
17
        /**
18
         * ContentRepository constructor.
19
         * @param $storagePath
20
         */
21
        public function __construct($storagePath)
22
        {
23
            $this->storagePath = $storagePath;
24
        }
25
26
        /**
27
         * @return \PDO
28
         */
29 View Code Duplication
        public function getContentDbHandle()
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...
30
        {
31
            if ($this->contentDbHandle === null) {
32
                $this->contentDbHandle = new \PDO('sqlite:' . $this->storagePath . DIRECTORY_SEPARATOR . 'content.db');
33
            }
34
            return $this->contentDbHandle;
35
        }
36
37
        /**
38
         * Prepare the sql statement
39
         * @param $sql
40
         * @return \PDOStatement
41
         * @throws \Exception
42
         */
43
        protected function getDbStatement($sql)
44
        {
45
            $db = $this->getContentDbHandle();
46
            $stmt = $db->query($sql);
47 View Code Duplication
            if ($stmt === false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
48
                $errorInfo = $db->errorInfo();
49
                $errorMsg = $errorInfo[2];
50
                throw new \RuntimeException('SQLite Exception: ' . $errorMsg . ' in SQL: <br /><pre>' . $sql . '</pre>');
51
            }
52
            return $stmt;
53
        }
54
55
        /**
56
         * @param Repository $repository
57
         * @param $document
58
         * @param $db
59
         * @param $documents
60
         * @param $key
61
         * @return mixed
62
         */
63
        private function setAssetsToDocumentFolders(Repository $repository, $document, $db, $documents, $key)
64
        {
65
            if ($document->type === 'folder') {
66
                $document->dbHandle = $db;
67
                $document->documentStorage = new DocumentStorage($repository);
68
                $documents[$key] = $document;
69
            }
70
71
            return $documents;
72
        }
73
74
        /**
75
         * @param Repository $repository
76
         * @param string $folderPath
77
         * @return array
78
         * @throws \Exception
79
         */
80
        public function getDocumentsWithState(Repository $repository, $folderPath = '/')
81
        {
82
            $db = $this->getContentDbHandle();
83
            $folderPathWithWildcard = $folderPath . '%';
84
85
            $ifRootIndex = 1;
86
            if ($folderPath === '/') {
87
                $ifRootIndex = 0;
88
            }
89
90
            $sql = '
91
            SELECT documents_unpublished.*,
92
            	   IFNULL(documents_published.state,"unpublished") as state,
93
            	   IFNULL(documents_published.publicationDate,NULL) as publicationDate,
94
            	   (documents_published.lastModificationDate != documents_unpublished.lastModificationDate) as unpublishedChanges 
95
              FROM documents_unpublished
96
		 LEFT JOIN documents_published
97
         		ON documents_published.path = documents_unpublished.path
98
             WHERE documents_unpublished.`path` LIKE ' . $db->quote($folderPathWithWildcard) . '
99
               AND substr(documents_unpublished.`path`, ' . (strlen($folderPath) + $ifRootIndex + 1) . ') NOT LIKE "%/%"
100
               AND length(documents_unpublished.`path`) > ' . (strlen($folderPath) + $ifRootIndex) . '
101
               AND documents_unpublished.path != ' . $db->quote($folderPath) . '
102
          ORDER BY documents_unpublished.`type` DESC, documents_unpublished.`path` ASC
103
        ';
104
            $stmt = $this->getDbStatement($sql);
105
106
107
            $documents = $stmt->fetchAll(\PDO::FETCH_CLASS, Document::class);
108
            foreach ($documents as $key => $document) {
109
                $documents = $this->setAssetsToDocumentFolders($repository, $document, $db, $documents, $key);
110
            }
111
            //dump($documents);
112
            return $documents;
113
        }
114
115
        /**
116
         * Get all documents and folders in a certain path
117
         *
118
         * @param Repository $repository
119
         * @param        $folderPath
120
         * @param string $state
121
         * @return array
122
         * @throws \Exception
123
         */
124
        public function getDocumentsByPath(Repository $repository, $folderPath, $state = 'published')
125
        {
126
            if (!in_array($state, Document::$DOCUMENT_STATES, true)) {
127
                throw new \RuntimeException('Unsupported document state: ' . $state);
128
            }
129
            $db = $this->getContentDbHandle();
130
            $folderPathWithWildcard = $folderPath . '%';
131
132
            $sql = 'SELECT *
133
              FROM documents_' . $state . '
134
             WHERE `path` LIKE ' . $db->quote($folderPathWithWildcard) . '
135
               AND substr(`path`, ' . (strlen($folderPath) + 1) . ') NOT LIKE "%/%"
136
               AND path != ' . $db->quote($folderPath) . '
137
          ORDER BY `type` DESC, `path` ASC';
138
            $stmt = $this->getDbStatement($sql);
139
140
            $documents = $stmt->fetchAll(\PDO::FETCH_CLASS, Document::class);
141
            foreach ($documents as $key => $document) {
142
                $documents = $this->setAssetsToDocumentFolders($repository, $document, $db, $documents, $key);
143
            }
144
            return $documents;
145
        }
146
147
        /**
148
         * @param \CloudControl\Cms\storage\Repository $repository
149
         * @param        $path
150
         * @param string $state
151
         * @return bool|Document
152
         * @throws \Exception
153
         */
154
        public function getDocumentByPath(Repository $repository, $path, $state = 'published')
155
        {
156
            if (!in_array($state, Document::$DOCUMENT_STATES, true)) {
157
                throw new \RuntimeException('Unsupported document state: ' . $state);
158
            }
159
            $db = $this->getContentDbHandle();
160
            $document = $this->fetchDocument('
161
            SELECT *
162
              FROM documents_' . $state . '
163
             WHERE path = ' . $db->quote($path) . '
164
        ');
165
            if ($document instanceof Document && $document->type === 'folder') {
166
                $document->dbHandle = $db;
167
                $document->documentStorage = new DocumentStorage($repository);
168
            }
169
            return $document;
170
        }
171
172
        /**
173
         * Return the result of the query as Document
174
         * @param $sql
175
         * @return mixed
176
         * @throws \Exception
177
         */
178
        protected function fetchDocument($sql)
179
        {
180
            $stmt = $this->getDbStatement($sql);
181
            return $stmt->fetchObject(Document::class);
182
        }
183
184
        /**
185
         * @param Repository $repository
186
         * @param $path
187
         * @return bool|Document
188
         * @throws \Exception
189
         */
190
        public function getDocumentContainerByPath(Repository $repository, $path)
191
        {
192
            $document = $this->getDocumentByPath($repository, $path, 'unpublished');
193
            if ($document === false) {
194
                return false;
195
            }
196
            $slugLength = strlen($document->slug);
197
            $containerPath = substr($path, 0, -$slugLength);
198
            if ($containerPath === '/') {
199
                return $this->getRootFolder();
200
            }
201
            if (substr($containerPath, -1) === '/') {
202
                $containerPath = substr($containerPath, 0, -1);
203
            }
204
            $containerFolder = $this->getDocumentByPath($repository, $containerPath, 'unpublished');
205
            return $containerFolder;
206
        }
207
208
        /**
209
         * Create a (non-existent) root folder Document and return it
210
         * @return Document
211
         */
212
        protected function getRootFolder()
213
        {
214
            $rootFolder = new Document();
215
            $rootFolder->path = '/';
216
            $rootFolder->type = 'folder';
217
            return $rootFolder;
218
        }
219
220
        /**
221
         * Returns the count of all documents stored in the db
222
         *
223
         * @param string $state
224
         *
225
         * @return int
226
         * @throws \Exception
227
         */
228
        public function getTotalDocumentCount($state = 'published')
229
        {
230
            if (!in_array($state, Document::$DOCUMENT_STATES, true)) {
231
                throw new \RuntimeException('Unsupported document state: ' . $state);
232
            }
233
            $db = $this->getContentDbHandle();
234
            $stmt = $db->query('
235
			SELECT count(*)
236
			  FROM documents_' . $state . '
237
			 WHERE `type` != "folder"
238
		');
239
            $result = $stmt->fetch(\PDO::FETCH_ASSOC);
240
            if (!is_array($result)) {
241
                return 0;
242
            }
243
            return (int)current($result);
244
        }
245
246
        /**
247
         * @return array
248
         * @throws \Exception
249
         */
250
        public function getPublishedDocumentsNoFolders()
251
        {
252
            $db = $this->getContentDbHandle();
253
            $sql = '
254
			SELECT *
255
			  FROM documents_published
256
			 WHERE `type` != "folder"
257
		';
258
            $stmt = $db->query($sql);
259
            $result = $stmt->fetchAll(\PDO::FETCH_CLASS, Document::class);
260 View Code Duplication
            if ($stmt === false || !$stmt->execute()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
261
                $errorInfo = $db->errorInfo();
262
                $errorMsg = $errorInfo[2];
263
                throw new \RuntimeException('SQLite Exception: ' . $errorMsg . ' in SQL: <br /><pre>' . $sql . '</pre>');
264
            }
265
            return $result;
266
        }
267
268
        /**
269
         * @param $path
270
         * @throws \Exception
271
         */
272
        public function publishDocumentByPath($path)
273
        {
274
            $this->publishOrUnpublishDocumentByPath($path);
275
        }
276
277
        /**
278
         * @param $path
279
         * @throws \Exception
280
         */
281
        public function unpublishDocumentByPath($path)
282
        {
283
            $this->publishOrUnpublishDocumentByPath($path, false);
284
        }
285
286
        /**
287
         * @param $path
288
         * @param bool $publish
289
         * @throws \Exception
290
         */
291
        public function publishOrUnpublishDocumentByPath($path, $publish = true)
292
        {
293
            $sql = 'DELETE FROM documents_published
294
					  WHERE `path` = :path';
295
            if ($publish) {
296
                $sql = '
297
				INSERT OR REPLACE INTO documents_published 
298
					  (`id`,`path`,`title`,`slug`,`type`,`documentType`,`documentTypeSlug`,`state`,`lastModificationDate`,`creationDate`,`publicationDate`,`lastModifiedBy`,`fields`,`bricks`,`dynamicBricks`)
299
				SELECT `id`,`path`,`title`,`slug`,`type`,`documentType`,`documentTypeSlug`,"published" as state,`lastModificationDate`,`creationDate`,' . time() . ' as publicationDate, `lastModifiedBy`,`fields`,`bricks`,`dynamicBricks`
300
				  FROM documents_unpublished
301
				 WHERE `path` = :path
302
			';
303
            }
304
            $db = $this->getContentDbHandle();
305
            $stmt = $db->prepare($sql);
306 View Code Duplication
            if ($stmt === false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
307
                $errorInfo = $db->errorInfo();
308
                $errorMsg = $errorInfo[2];
309
                throw new \RuntimeException('SQLite Exception: ' . $errorMsg . ' in SQL: <br /><pre>' . $sql . '</pre>');
310
            }
311
            $stmt->bindValue(':path', $path);
312
            $stmt->execute();
313
        }
314
315
        public function cleanPublishedDeletedDocuments()
316
        {
317
            $sql = '   DELETE FROM documents_published
318
						 WHERE documents_published.path IN (
319
						SELECT documents_published.path
320
						  FROM documents_published
321
					 LEFT JOIN documents_unpublished
322
							ON documents_unpublished.path = documents_published.path
323
						 WHERE documents_unpublished.path IS NULL
324
		)';
325
            $stmt = $this->getDbStatement($sql);
326
            $stmt->execute();
327
        }
328
329
        /**
330
         * Save the document to the database
331
         *
332
         * @param Document $documentObject
333
         * @param string $state
334
         *
335
         * @return bool
336
         * @throws \Exception
337
         */
338
        public function saveDocument($documentObject, $state = 'published')
339
        {
340
            if (!in_array($state, Document::$DOCUMENT_STATES, true)) {
341
                throw new \RuntimeException('Unsupported document state: ' . $state);
342
            }
343
            $db = $this->getContentDbHandle();
344
            $stmt = $this->getDbStatement('
345
            INSERT OR REPLACE INTO documents_' . $state . ' (`path`,`title`,`slug`,`type`,`documentType`,`documentTypeSlug`,`state`,`lastModificationDate`,`creationDate`,`lastModifiedBy`,`fields`,`bricks`,`dynamicBricks`)
346
            VALUES(
347
              ' . $db->quote($documentObject->path) . ',
348
              ' . $db->quote($documentObject->title) . ',
349
              ' . $db->quote($documentObject->slug) . ',
350
              ' . $db->quote($documentObject->type) . ',
351
              ' . $db->quote($documentObject->documentType) . ',
352
              ' . $db->quote($documentObject->documentTypeSlug) . ',
353
              ' . $db->quote($documentObject->state) . ',
354
              ' . $db->quote($documentObject->lastModificationDate) . ',
355
              ' . $db->quote($documentObject->creationDate) . ',
356
              ' . $db->quote($documentObject->lastModifiedBy) . ',
357
              ' . $db->quote(json_encode($documentObject->fields)) . ',
358
              ' . $db->quote(json_encode($documentObject->bricks)) . ',
359
              ' . $db->quote(json_encode($documentObject->dynamicBricks)) . '
360
            )
361
        ');
362
            return $stmt->execute();
363
        }
364
365
        /**
366
         * Delete the document from the database
367
         * If it's a folder, also delete it's contents
368
         *
369
         * @param Repository $repository
370
         * @param        $path
371
         * @throws \Exception
372
         */
373
        public function deleteDocumentByPath(Repository $repository, $path)
374
        {
375
            $db = $this->getContentDbHandle();
376
            $documentToDelete = $this->getDocumentByPath($repository, $path, 'unpublished');
377
            if ($documentToDelete instanceof Document) {
378
                if ($documentToDelete->type === 'document') {
379
                    $stmt = $this->getDbStatement('
380
                    DELETE FROM documents_unpublished
381
                          WHERE path = ' . $db->quote($path) . '
382
                ');
383
                    $stmt->execute();
384
                } elseif ($documentToDelete->type === 'folder') {
385
                    $folderPathWithWildcard = $path . '%';
386
                    $stmt = $this->getDbStatement('
387
                    DELETE FROM documents_unpublished
388
                          WHERE (path LIKE ' . $db->quote($folderPathWithWildcard) . '
389
                            AND substr(`path`, ' . (strlen($path) + 1) . ', 1) = "/")
390
                            OR path = ' . $db->quote($path) . '
391
                ');
392
                    $stmt->execute();
393
                }
394
            }
395
        }
396
    }
397
398
399
}