Passed
Push — develop ( 7eec78...e0880f )
by Jens
02:21
created

DocumentApiComponent::getSearchDocumentsResponse()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 13
nc 3
nop 0
dl 0
loc 17
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * Created by jensk on 26-3-2018.
4
 */
5
6
namespace CloudControl\Cms\components;
7
8
9
use CloudControl\Cms\cc\Application;
10
use CloudControl\Cms\cc\Request;
11
use CloudControl\Cms\cc\ResponseHeaders;
12
use CloudControl\Cms\components\api\Response;
13
use CloudControl\Cms\search\CharacterFilter;
14
use CloudControl\Cms\search\results\SearchSuggestion;
15
use CloudControl\Cms\search\Search;
16
use CloudControl\Cms\search\Tokenizer;
17
use CloudControl\Cms\storage\entities\Document;
18
use CloudControl\Cms\storage\Storage;
19
use CloudControl\Cms\storage\storage\DocumentStorage;
20
21
class DocumentApiComponent extends CachableBaseComponent
22
{
23
    const GET_PARAMETER_PATH = 'path';
24
    const GET_PARAMETER_Q = 'q';
25
    /**
26
     * @var Response
27
     */
28
    protected $response;
29
30
    /**
31
     * @param Storage $storage
32
     */
33
    public function run(Storage $storage)
34
    {
35
        parent::run($storage);
36
        ResponseHeaders::add(ResponseHeaders::HEADER_CONTENT_TYPE, ResponseHeaders::HEADER_CONTENT_TYPE_CONTENT_APPLICATION_JSON);
37
        $this->setResponse();
38
    }
39
40
    private function setResponse()
41
    {
42
        try {
43
44
            if (isset($_GET[self::GET_PARAMETER_Q])) {
45
                $this->response = $this->getSearchDocumentsResponse();
46
                return;
47
            }
48
49
            if (isset($_GET[self::GET_PARAMETER_PATH])) {
50
                $this->response = $this->getDocumentsByPathResponse();
51
                return;
52
            }
53
            $this->response = '{"swagger":"2.0","info":{"description":"This is documentation for the DocumentApiComponent of the Cloud Control Framework & CMS. See https://getcloudcontrol.org. Additional documentation regarding the DocumentApiComponent can be found here: https://github.com/jenskooij/cloudcontrol/wiki/DocumentApiComponent","title":"DocumentApiComponent for Cloud Control - Framework & CMS","contact":{"name":"Cloud Control - Framework & CMS","url":"https://getcloudcontrol.org"},"license":{"name":"MIT","url":"https://github.com/jenskooij/cloudcontrol/blob/master/LICENSE"},"version":"1.0.0"},"basePath":"' . Request::$subfolders . '","paths":{"' . Request::$subfolders . Request::$relativeUri . '":{"get":{"summary":"Retrieve documents","produces":["application/json"],"parameters":[{"name":"q","in":"query","description":"Search query","required":false,"type":"string"},{"name":"path","in":"query","description":"The (folder) path of which you want to see the contents","required":false,"type":"string"}],"responses":{"200":{"description":"Successful operation","schema":{"$ref":"#/definitions/ApiResponse"}},"default":{"schema":{"type":"string","example":"{}"},"description":"When no parameters present, shows the swagger definition"}}}}},"definitions":{"ApiResponse":{"type":"object","properties":{"success":{"type":"boolean","title":"Wheter or not the call was processed succesful"},"results":{"type":"array","title":"The array of Documents that were found","items":{"$ref":"#/definitions/Document"}},"error":{"title":"If an error occured, it will be displayed, empty if not.","type":"string"},"folder":{"type":"string","title":"Path of the currently selected folder, by using the id parameter","example":"/folder"},"searchSuggestions":{"type":"array","items":{"type":"array","items":{"$ref":"#/definitions/SearchSuggestion"}}}}},"Document":{"type":"object","properties":{"id":{"type":"string","title":"The Document identifier","example":"1"},"path":{"type":"string","title":"The Document path"},"title":{"type":"string","title":"The Document title"},"slug":{"type":"string","title":"The Document slug"},"type":{"type":"string","title":"The Document type","enum":["document","folder"]},"documentType":{"type":"string","title":"The Document DocumentType, as defined in the CMS"},"documentTypeSlug":{"type":"string","title":"The Document DocumentType slug"},"state":{"type":"string","title":"The publication state for this document","enum":["published","unpublished"]},"lastModificationDate":{"type":"string","title":"The Document\'s last modification timestamp","example":"0"},"publicationDate":{"type":"string","title":"The Document\'s publication timestamp","example":"0"}}},"SearchSuggestion":{"type":"object","properties":{"original":{"type":"string","title":"The query that was retrieved from parameter q","example":"kyeword"},"term":{"type":"string","title":"An existing term that is closest to the original","example":"keyword"},"editDistance":{"type":"string","title":"The amount of changes were made to get from the term to the original","example":"2"}}}}}';
0 ignored issues
show
Documentation Bug introduced by
It seems like '{"swagger":"2.0","info"...al","example":"2"}}}}}' of type string is incompatible with the declared type CloudControl\Cms\components\api\Response of property $response.

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...
54
            return;
55
        } catch (\Exception $e) {
56
            $error = $e->getFile() . ':' . $e->getLine() . ' ' . $e->getMessage();
57
            $this->response = new Response(array(), false, $error);
58
            return;
59
        }
60
    }
61
62
    /**
63
     * @return Document
64
     * @throws \RuntimeException
65
     */
66
    private function getDococumentPathPath()
67
    {
68
        $path = $_GET[self::GET_PARAMETER_PATH];
69
        $db = $this->storage->getRepository()->getContentRepository()->getContentDbHandle();
70
        $stmt = $this->getPDOStatement($db, $this->getDocumentByPathSql($db, $path));
71
        return $stmt->fetchObject(Document::class);
72
    }
73
74
    /**
75
     * @param \PDO $db
76
     * @param int $path
77
     * @return string
78
     */
79
    private function getDocumentByPathSql($db, $path)
80
    {
81
        return 'SELECT *
82
              FROM documents_published
83
             WHERE path = ' . $db->quote($path) . '
84
        ';
85
    }
86
87
    /**
88
     * @param \PDO $db
89
     * @param string $sql
90
     * @return \PDOStatement
91
     * @throws \RuntimeException
92
     */
93
    private function getPDOStatement($db, $sql)
94
    {
95
        $stmt = $db->query($sql);
96
        if ($stmt === false) {
97
            $errorInfo = $db->errorInfo();
98
            $errorMsg = $errorInfo[2];
99
            throw new \RuntimeException('SQLite Exception: ' . $errorMsg . ' in SQL: <br /><pre>' . $sql . '</pre>');
100
        }
101
        return $stmt;
102
    }
103
104
    /**
105
     * @return Response
106
     * @throws \RuntimeException
107
     */
108
    private function getSingleDocumentResponse()
109
    {
110
        $document = $this->getDococumentPathPath();
111
112
        if ($document === false) {
0 ignored issues
show
introduced by
The condition $document === false is always false.
Loading history...
113
            return new Response();
114
        }
115
116
        if ($document->type === 'folder') {
117
            return $this->getFolderResponse($document);
118
        }
119
120
        $documentContent = $this->getDocumentContent($document);
121
        $document->documentContent = $documentContent;
122
123
        return new Response($document);
124
    }
125
126
    /**
127
     * @param Application $application
128
     */
129
    public function render($application = null)
130
    {
131
        $this->renderedContent = $this->response;
132
    }
133
134
    /**
135
     * @return Response
136
     * @throws \Exception
137
     */
138
    private function getDocumentsByPathResponse()
139
    {
140
        $path = $_GET[self::GET_PARAMETER_PATH];
141
        if ($path[0] === '/') {
142
            $path = substr($path, 1);
143
        }
144
        $folderDocument = $this->storage->getDocuments()->getDocumentFolderBySlug($path);
145
        if ($folderDocument !== false && $folderDocument->type === 'folder') {
146
            return $this->getFolderResponse($folderDocument);
0 ignored issues
show
Bug introduced by
It seems like $folderDocument can also be of type true; however, parameter $document of CloudControl\Cms\compone...nt::getFolderResponse() does only seem to accept CloudControl\Cms\storage\entities\Document, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

146
            return $this->getFolderResponse(/** @scrutinizer ignore-type */ $folderDocument);
Loading history...
147
        }
148
149
        return $this->getSingleDocumentResponse();
150
    }
151
152
    /**
153
     * @return Response
154
     * @throws \Exception
155
     */
156
    private function getSearchDocumentsResponse()
157
    {
158
        $rawResults = $this->getRawResults();
159
        $results = array();
160
        $suggestions = array();
161
        foreach ($rawResults as $rawResult) {
162
            if ($rawResult instanceof SearchSuggestion) {
163
                $suggestions[] = $rawResults;
164
                continue;
165
            }
166
            $result = $rawResult->getDocument();
167
            $result->searchInfo = $rawResult;
168
            $results[] = $result;
169
        }
170
        $response = new Response($results);
171
        $response->searchSuggestions = $suggestions;
172
        return $response;
173
    }
174
175
    /**
176
     * @param Document $document
177
     * @return \stdClass
178
     */
179
    private function getDocumentContent($document)
180
    {
181
        $documentContent = new \stdClass();
182
        $documentContent->fields = $document->fields;
183
        $documentContent->bricks = $document->bricks;
184
        $documentContent->dynamicBricks = $document->dynamicBricks;
185
        return $documentContent;
186
    }
187
188
    /**
189
     * @return array
190
     * @throws \Exception
191
     */
192
    private function getRawResults()
193
    {
194
        $filteredQuery = new CharacterFilter($_GET[self::GET_PARAMETER_Q]);
195
        $tokenizer = new Tokenizer($filteredQuery);
196
        $search = new Search($this->storage);
197
        $rawResults = $search->getDocumentsForTokenizer($tokenizer);
198
        return $rawResults;
199
    }
200
201
    /**
202
     * @param Document $document
203
     * @return Response
204
     * @throws \RuntimeException
205
     */
206
    private function getFolderResponse($document)
207
    {
208
        if ($document->type !== 'folder') {
209
            return new Response();
210
        }
211
        $document->dbHandle = $this->storage->getContentDbHandle();
212
        $document->documentStorage = new DocumentStorage($this->storage->getRepository());
213
        $response = new Response($document->getContent());
214
        $response->folder = $document->path;
215
        return $response;
216
    }
217
218
219
}