Completed
Push — 2.0 ( d6e0b5...aaf296 )
by Christopher
02:50
created

ServeController::search()   B

Complexity

Conditions 4
Paths 15

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 26
rs 8.5806
cc 4
eloc 15
nc 15
nop 1
1
<?php
2
/**
3
 * Licensed under The GPL-3.0 License
4
 * For full copyright and license information, please see the LICENSE.txt
5
 * Redistributions of files must retain the above copyright notice.
6
 *
7
 * @since    2.0.0
8
 * @author   Christopher Castro <[email protected]>
9
 * @link     http://www.quickappscms.org
10
 * @license  http://opensource.org/licenses/gpl-3.0.html GPL-3.0 License
11
 */
12
namespace Content\Controller;
13
14
use Cake\Collection\Collection;
15
use Cake\Datasource\EntityInterface;
16
use Cake\I18n\I18n;
17
use Cake\Network\Exception\ForbiddenException;
18
use Content\Error\ContentNotFoundException;
19
20
/**
21
 * Content serve controller.
22
 *
23
 * For handling all public content-rendering requests.
24
 *
25
 * @property \Content\Model\Table\ContentsTable $Contents
26
 */
27
class ServeController extends AppController
28
{
29
30
    /**
31
     * Components used by this controller.
32
     *
33
     * @var array
34
     */
35
    public $components = [
36
        'Comment.Comment',
37
        'Paginator',
38
        'RequestHandler',
39
    ];
40
41
    /**
42
     * An array containing the names of helpers controllers uses.
43
     *
44
     * @var array
45
     */
46
    public $helpers = ['Time', 'Paginator'];
47
48
    /**
49
     * Paginator settings.
50
     *
51
     * Used by `search()` and `rss()`.
52
     *
53
     * @var array
54
     */
55
    public $paginate = [
56
        'limit' => 10,
57
    ];
58
59
    /**
60
     * Redirects to ServeController::home()
61
     *
62
     * @return void
63
     */
64
    public function index()
65
    {
66
        $this->redirect(['plugin' => 'Content', 'controller' => 'serve', 'action' => 'home']);
67
    }
68
69
    /**
70
     * Site's home page.
71
     *
72
     * Gets a list of all promoted contents, so themes may render them in their
73
     * front-page layout. The view-variable `contents` holds all promoted contents,
74
     * themes might render this contents using this variable.
75
     *
76
     * @return void
77
     */
78
    public function home()
79
    {
80
        $this->loadModel('Content.Contents');
81
        $contents = $this->Contents
82
            ->find('all')
83
            ->where([
84
                'Contents.promote' => 1,
85
                'Contents.status >' => 0,
86
                'Contents.language IN' => ['', null, I18n::locale()]
87
            ])
88
            ->order(['Contents.sticky' => 'DESC', 'Contents.created' => 'DESC'])
89
            ->limit((int)option('site_contents_home'));
90
91
        $this->set('contents', $contents);
92
        $this->viewMode('teaser');
93
    }
94
95
    /**
96
     * Content's detail page.
97
     *
98
     * @param string $contentTypeSlug Content's type-slug. e.g. `article`, `basic-page`
99
     * @param string $contentSlug Content's slug. e.g. `this-is-an-article`
100
     * @return \Cake\Network\Response|null
101
     * @throws \Content\Error\ContentNotFoundException When content is not found
102
     * @throws \Cake\Network\Exception\ForbiddenException When user can't access
103
     *  this content due to role restrictions
104
     */
105
    public function details($contentTypeSlug, $contentSlug)
106
    {
107
        $this->loadModel('Content.Contents');
108
        $conditions = [
109
            'Contents.slug' => $contentSlug,
110
            'Contents.content_type_slug' => $contentTypeSlug,
111
        ];
112
113
        if (!$this->request->is('userAdmin')) {
114
            $conditions['Contents.status >'] = 0;
115
        }
116
117
        $content = $this->Contents->find()
118
            ->where($conditions)
119
            ->contain(['ContentTypes', 'Roles'])
120
            ->first();
121
122
        if (!$content) {
123
            throw new ContentNotFoundException(__d('content', 'The requested page was not found.'));
124
        } elseif (!$content->isAccessible()) {
125
            throw new ForbiddenException(__d('content', 'You have not sufficient permissions to see this page.'));
126
        }
127
128
        if (!empty($content->language) && $content->language != I18n::locale()) {
129
            if ($redirect = $this->_calculateRedirection($content)) {
130
                $this->redirect($redirect);
131
                return $this->response;
132
            }
133
            throw new ContentNotFoundException(__d('content', 'The requested page was not found.'));
134
        }
135
136
        // Post new comment logic
137
        if ($content->comment_status > 0) {
138
            $content->set('comments', $this->Contents->find('comments', ['for' => $content->id]));
139
            $this->Comment->config('visibility', $content->comment_status);
140
            $this->Comment->post($content);
141
        }
142
143
        $this->set('content', $content);
144
        $this->viewMode('full');
145
    }
146
147
    /**
148
     * Contents search engine page.
149
     *
150
     * @param string $criteria A search criteria. e.g.: `"this phrase" -"but not this" OR -hello`
151
     * @return void
152
     */
153
    public function search($criteria)
154
    {
155
        $this->loadModel('Content.Contents');
156
157
        try {
158
            $contents = $this->Contents->search($criteria);
159
            if ($contents->clause('limit')) {
160
                $this->paginate['limit'] = $contents->clause('limit');
161
            }
162
163
            // TODO: ask search-engine for operator presence
164
            if (strpos($criteria, 'language:') === false) {
165
                $contents = $contents->where([
166
                    'Contents.status >' => 0,
167
                    'Contents.language IN' => ['', null, I18n::locale()] // any or concrete
168
                ]);
169
            }
170
171
            $contents = $this->paginate($contents);
172
        } catch (\Exception $e) {
173
            $contents = new Collection([]);
174
        }
175
176
        $this->set(compact('contents', 'criteria'));
177
        $this->viewMode('search-result');
178
    }
179
180
    /**
181
     * RSS feeder.
182
     *
183
     * Similar to `ServeController::search()` but it uses `rss` layout instead of
184
     * default layout.
185
     *
186
     * @param string $criteria A search criteria. e.g.: `"this phrase" -"but not this" OR -hello`
187
     * @return void
188
     */
189
    public function rss($criteria)
190
    {
191
        $this->loadModel('Content.Contents');
192
193
        try {
194
            $contents = $this->Contents
195
                ->search($criteria)
196
                ->limit(10);
197
        } catch (\Exception $e) {
198
            $contents = [];
199
        }
200
201
        $this->set(compact('contents', 'criteria'));
202
        $this->viewMode('rss');
203
        $this->RequestHandler->renderAs($this, 'rss');
204
        $this->RequestHandler->respondAs('xml');
205
    }
206
207
    /**
208
     * Calculates the URL to which visitor should be redirected according to
209
     * content's & visitor's language.
210
     *
211
     * @param \Cake\Datasource\EntityInterface $content Content to inspect
212
     * @return string Redirection URL, empty on error
213
     */
214
    protected function _calculateRedirection(EntityInterface $content)
215
    {
216
        foreach (['translation', 'parent'] as $method) {
217
            if ($has = $content->{$method}()) {
218
                return option('url_locale_prefix') ? '/' . $has->get('language') . stripLanguagePrefix($has->get('url')) : $has->get('url');
219
            }
220
        }
221
        return '';
222
    }
223
}
224