Passed
Push — master ( f61691...1918f3 )
by Jens
07:18
created

ContentRepository::getDocumentsWithState()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 34
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

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